有没有办法创建一个不会污染其实例的属性名称空间的Python类方法?
我想提供一个可以在Python2.7类对象上使用的方法,但不会污染其实例的属性名称空间。有没有办法做到这一点有没有办法创建一个不会污染其实例的属性名称空间的Python类方法?,python,python-2.7,oop,Python,Python 2.7,Oop,我想提供一个可以在Python2.7类对象上使用的方法,但不会污染其实例的属性名称空间。有没有办法做到这一点 >>> class Foo(object): ... @classmethod ... def ugh(cls): ... return 33 ... >>> Foo.ugh() 33 >>> foo = Foo() >>> foo.ugh() 33 ugh不在命名空间中: >>>
>>> class Foo(object):
... @classmethod
... def ugh(cls):
... return 33
...
>>> Foo.ugh()
33
>>> foo = Foo()
>>> foo.ugh()
33
ugh
不在命名空间中:
>>> foo.__dict__
{}
但是,属性查找的规则取决于缺少名称的实例的类型。您可以覆盖Foo.\uuuu getattribute\uuu
以防止出现这种情况
class Foo(object):
@classmethod
def ugh(cls):
return 33
def __getattribute__(self, name):
if name == 'ugh':
raise AttributeError("Access to class method 'ugh' block from instance")
return super(Foo,self).__getattribute__(name)
这将产生:
>>> foo = Foo()
>>> foo.ugh()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "tmp.py", line 8, in __getattribute__
raise AttributeError("Access to class method 'ugh' block from instance")
AttributeError: Access to class method 'ugh' block from instance
>>> Foo.ugh()
33
foo=foo()
>>>foo.ugh()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“tmp.py”,第8行,在__
raise AttributeError(“从实例访问类方法'ugh'块”)
AttributeError:从实例访问类方法“ugh”块
>>>Foo.ugh()
33
您必须使用在任何属性访问时无条件调用的
\uuuuuu getattribute\uuuu
,而不是只有在正常查找(包括检查类型的命名空间)失败后才调用的\uuuu getattr\uuuuuu
。是的,您可以在元类中创建方法
class FooMeta(type):
# No @classmethod here
def ugh(cls):
return 33
class Foo(object):
__metaclass__ = FooMeta
Foo.ugh() # returns 33
Foo().ugh() # AttributeError
请注意,元类是一种强大的功能,如果不必要,则不鼓励使用元类。特别是,如果父类具有不同的元类,则多重继承需要特别小心。您可以对classmethod描述符进行子类化:
class classonly(classmethod):
def __get__(self, obj, type):
if obj: raise AttributeError
return super(classonly, self).__get__(obj, type)
这就是它的行为方式:
class C(object):
@classonly
def foo(cls):
return 42
>>> C.foo()
42
>>> c=C()
>>> c.foo()
AttributeError
这将调用描述符调用(而是由\uu getattribute\uu
的默认实现调用):
>>C.uuu dict_uuuuuu['foo'].uuuu get_uuuu(无,C)
>>>C.uuu dict_uuuuuuu['foo'].uuuu get_uuuuu(C,类型(C))
属性错误
必读内容:和。Python使用名称模糊不清来减少意外访问。格式为\uuu name
的方法和对象变量转换为\u ClassName\uu name
。Python在类上编译方法时会自动更改名称,但不会更改子类的名称
我可以在类中使用私有方法
>>> class A(object):
... def __private(self):
... print('boo')
... def hello(self):
... self.__private()
...
>>>
>>> A().hello()
boo
但不是在课堂之外
>>> A().__private()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute '__private'
>>>
>>A()。\uuu private()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:'对象没有属性'\uu private'
>>>
或者在子类中
>>> class B(A):
... def hello2(self):
... self.__private()
...
>>>
>>> B().hello()
boo
>>> B().hello2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in hello2
AttributeError: 'B' object has no attribute '_B__private'
>>B类(A):
... def hello2(自我):
... self.\uuu private()
...
>>>
>>>你好
喝倒采
>>>B().hello2()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第3行,在hello2中
AttributeError:“B”对象没有属性“\u B\u\u private”
从技术上讲,ugh
不在实例的命名空间中(foo.\uu dict\uuu
);由于Python的查找算法,可以通过实例简单地访问它?(似乎证实了:例如,a.x有一个查找链,从a开始,然后键入(a)。\uuuuDict\uuuI['x'],并继续查找(a)类型的基类,不包括元类。
)我想在类对象上创建一些特殊的魔法,但我不想让使用我的类的同事从实例中意外调用它,因为他们很好奇。如果有一种方法可以抑制可见性那就太好了。另一个强大的功能是控制内省的\uuuuu dir\uuuuu
。@stephernauch当然;我不想阻止那些知道自己在做什么的人,但我确实想限制偶然的错误。在我的例子中,我的同事都是Python初学者,墨菲定律说,他们会找到一种方法,克服任何可能的绊倒危险。(当我假设不是这样的时候,它会导致我必须修复的问题。)使用元类的成本是多少?这似乎正是我正在寻找的功能,只要我能保持它们的功能简单,这将是我想要利用的东西。我将潜在地制造数千个实例对象——如果我使用元类,它们会花费大量额外内存吗?@JasonS:主要问题是元类非常强大,可以用来对类执行许多奇怪的操作(例如,您可以重写特殊方法,如\uuuu add\uuu
,使Foo+Foo
成为有意义的表达式)。其中许多会降低代码的可读性。如果您使用它们来覆盖加法或此类简单操作的含义,则会产生混淆,但除此之外,它们只是另一个工具元类,不一定能很好地相互配合。继承自B
的A
元类必须是“兼容的"使用元类B
;在实践中,它在某种程度上限制了你想在何时何地使用元类。我的大脑在冒烟……你能详细说明一下吗?表面上看这似乎很简单,但我想我不明白@classmethod
在引擎盖下实际做了什么。嗯。我试过了,但似乎不起作用在Python 2.7Aha中,这是一个超级调用。元类可以覆盖类的定义和对象创建的许多方面,并且可以通过继承产生复杂的副作用。描述符是一种覆盖getattr和setattr的对象类型,不能对类的其余部分产生任何副作用。正如我所知,在AB之外在CMeta层次结构中,stdlib(py3的)只使用了两个元类(一个在enum中,一个在ctypes中),但大量使用了标准的@classmethod装饰符和自定义描述符。我会跟随他们的领导。很酷,谢谢!我对它做了一些调整,为AttributeError
添加了一条有用的错误消息。
>>> class B(A):
... def hello2(self):
... self.__private()
...
>>>
>>> B().hello()
boo
>>> B().hello2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in hello2
AttributeError: 'B' object has no attribute '_B__private'