質問

class Foo(object):
    __slots__ = ('a',)

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

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

If I'm using this code, this doesn't work:

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

Why?

According to the python docs, __slots__ are implemented :

__slots__ are implemented at the class level by creating descriptors (Implementing Descriptors) for each variable name. As a result, class attributes cannot be used to set default values for instance variables defined by __slots__; otherwise, the class attribute would overwrite the descriptor assignment.

But descriptors can cope with inheritance (at least if written in pure python).

Does anyone get know, why this is not working with __slots__?

Edit: It seems like descriptors are generally not working with super(), if you're trying to write (read works, though). So my question would rather be: Why are descriptors read-only, if invoked with super()?

役に立ちましたか?

解決

super() doesn't return the descriptor, it returns the result of getting the descriptor. It doesn't return functions either, it returns the bound method; functions act as descriptors too, and their .__get__() method returns a method.

Because there is no a defined on the instance, there is no value and the descriptor .__get__() raises an AttributeError.

Things work if you define a on instances of Foo:

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

So, accessing a __slots__ descriptor without a value raises an 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

but give the instance a value, and the AttributeError goes away:

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

Now super() can find the result of the descriptor just fine (demonstrating with a different attribute name to not clobber self.a):

>>> class Bar(Foo):
...     __slots__ = ('b',)
...     @property
...     def b(self):
...         return super(Bar, self).a
... 
>>> Bar().a
'spam'
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top