除了否定值之外,您的所有代码所做的都是调用父类__setattr__
,这正是没有您的__setattr__
方法会发生的事情。所以简短的回答是:当然你可以定义一个__setattr__
.
你不能做的是重新定义__setattr__
使用self.__dict__
,因为带有插槽的类的实例没有属性__dict__
。但是这样的实例确实有一个self.x
属性,它的内容只是没有存储在实例上的字典中。
相反,槽值存储在与__dict__
实例字典相同的位置,否则会被存储;在对象堆上。空间是为len(__slots__)
引用保留的,类上的描述符代表您访问这些引用。
因此,在__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 中,它一直是海龟,你当然会在对象上查找该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})