除了否定值之外,您的所有代码所做的都是调用父类__setattr__,这正是没有您的__setattr__ 方法时会发生的情况。所以简短的回答是:当然你可以定义一个__setattr__。
您不能做的是重新定义__setattr__ 以使用self.__dict__,因为具有插槽的类的实例没有 __dict__ 属性。但是这样的实例确实有一个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})