假设我有一个定义__slots__
的课程:
class Foo(object):
__slots__ = ['x']
def __init__(self, x=1):
self.x = x
# will the following work?
def __setattr__(self, key, value):
if key == 'x':
object.__setattr__(self, name, -value) # Haha - let's set to minus x
我可以为它定义__setattr__()
吗?
由于Foo
没有__dict__
,它会更新什么?
答案 0 :(得分:10)
除了否定值之外,你的所有代码都会调用父类__setattr__
,这正是没有__setattr__
方法的情况。所以简短的回答是:当然你可以定义一个__setattr__
。
您不能做的是重新定义__setattr__
以使用self.__dict__
,因为带插槽的类的实例不具有 __dict__
属性。但是这样的实例 do 具有self.x
属性,它的内容不会存储在实例的字典中。
相反,插槽值存储在__dict__
实例字典以其他方式存储的相同位置;在对象堆上。空间保留用于len(__slots__)
个引用,并且该类的descriptors代表您访问这些引用。
因此,在__setattr__
钩子中,您可以直接调用这些描述符:
def __setattr__(self, key, value):
if key == 'x':
Foo.__dict__[key].__set__(self, -value)
有趣的绕行:是的,在没有__slots__
属性的类上,是一个描述符,可以让您访问实例的__dict__
对象:
>>> class Bar(object): pass
...
>>> Bar.__dict__['__dict__']
<attribute '__dict__' of 'Bar' objects>
>>> Bar.__dict__['__dict__'].__get__(Bar(), Bar)
{}
普通实例可以查找self.__dict__
的方式。这让你想知道找到Bar.__dict__
对象的位置。在Python中,它是turtles all the way down,你当然会在type
对象上看 对象:
>>> type.__dict__['__dict__']
<attribute '__dict__' of 'type' objects>
>>> type.__dict__['__dict__'].__get__(Bar, type)
dict_proxy({'__dict__': <attribute '__dict__' of 'Bar' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Bar' objects>, '__doc__': None})