【问题标题】:Can __setattr__() can be defined in a class with __slots__?可以在具有 __slots__ 的类中定义 __setattr__() 吗?
【发布时间】:2013-11-03 04:32:25
【问题描述】:

假设我有一个定义__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


    【解决方案1】:

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

    【讨论】:

    • dict 在这里工作吗?是不是因为 dict 的有效地址和堆项是一样的,这有点像彩蛋?还是您的意思是 slots
    • @CorleyBrigman:不要将 class__dict__instance__dict__ 混淆。 Foo 类的实例没有 __dict__ 属性。
    • @CorleyBrigman:而Foo 实例没有__dict__ 属性,因为Foo.__dict__['__dict__'] 引发了KeyError
    • @MartijnPieters - 不知道我明白了。 object 是否有 __dict__,即使 Foo 没有?我猜不是,在这种情况下,调用object.__setattr__() 会发生什么变化?
    • @bavaza: object.__dict__ 确实存在,但这不是实例会使用的。 object.__setattr__ 会在查找 instance.__dict__ 之前查找数据描述符,并且 Foo.__dict__['x'] 数据描述符(它同时具有 __get____set__ 钩子),所以 instance.__dict__ object.__setattr__ 从未查找过。
    猜你喜欢
    • 2018-02-16
    • 1970-01-01
    • 2015-09-12
    • 2021-05-07
    • 2013-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-27
    相关资源
    最近更新 更多