可以使用__slots__在类中定义__setattr __()吗?

最后发布: 2013-10-24 12:49:18


问题

假设我有一个定义__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__ ,它会更新什么?

python python-internals slots setattr
回答

除了否定值之外,你的所有代码都会调用父类__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})