【问题标题】:Python: __slots__ and its usage of descriptorsPython:__slots__ 及其描述符的使用
【发布时间】:2012-12-24 04:09:09
【问题描述】:
class Foo(object):
    __slots__ = ('a',)

class Bar(Foo):
    @property
    def a(self):
        return super(Bar, self).a

 super(Bar, Bar()).a = 4

如果我使用这个代码,这不起作用:

>>> super(Bar, Bar()).a = 4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'super' object has no attribute 'a'

为什么?

根据python docs__slots__分别实现:

__slots__ 在类级别通过为每个变量名创建描述符(实现描述符)来实现。结果,类 属性不能用于设置实例变量的默认值 由__slots__定义;否则,类属性将覆盖 描述符分配。

但描述符可以处理继承(至少如果用纯 python 编写的话)。

有谁知道,为什么这不适用于__slots__

编辑:如果你想写的话,似乎描述符通常不适用于super()(不过,读作品)。所以我的问题宁愿是:如果使用super() 调用,为什么描述符是只读的?

【问题讨论】:

    标签: python python-2.7 cpython python-3.2 slots


    【解决方案1】:

    super() 不返回描述符,它返回getting 描述符的result。它也不返回函数,它返回绑定的方法;函数也充当描述符,它们的.__get__() 方法返回一个方法。

    因为在实例上没有定义a,所以没有值并且描述符.__get__()引发了一个AttributeError。

    如果您在 Foo 的实例上定义 a,一切都会奏效:

    class Foo(object):
        __slots__ = ('a',)
        def __init__(self):
            self.a = 'spam'
    

    因此,访问不带值的__slots__ 描述符会引发AttributeError

    >>> class Foo(object):
    ...     __slots__ = ('a',)
    ... 
    >>> Foo.a
    <member 'a' of 'Foo' objects>
    >>> Foo().a
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: a
    >>> Foo.a.__get__(Foo(), Foo)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: a
    

    但给实例一个值,AttributeError 消失:

    >>> class Foo(object):
    ...     __slots__ = ('a',)
    ...     def __init__(self):
    ...         self.a = 'spam'
    ... 
    >>> Foo.a.__get__(Foo(), Foo)
    'spam'
    

    现在super() 可以找到描述符的结果就好了(演示用不同的属性名称不破坏self.a):

    >>> class Bar(Foo):
    ...     __slots__ = ('b',)
    ...     @property
    ...     def b(self):
    ...         return super(Bar, self).a
    ... 
    >>> Bar().a
    'spam'
    

    【讨论】:

    • 是的。我也刚想通。真的是因为super很特别。
    • @DavidHalter:不是真的;这是因为当实例中缺少该属性时,描述符会引发 AttributeError
    • 是的,我现在明白了 :-) 谢谢!
    猜你喜欢
    • 2021-04-08
    • 1970-01-01
    • 2020-08-12
    • 1970-01-01
    • 2011-04-17
    • 2017-06-19
    • 2017-01-14
    • 2011-06-22
    相关资源
    最近更新 更多