在使用@property装饰器时,在属性的setter方法中使用super()会引发AttributeError

Vor*_*ity 10 python python-2.7

尝试覆盖子类中的属性时,我对此行为有点困惑.

第一个例子设置了两个类,ParentChild. Parent继承自object,而Child继承自Parent.该属性a是使用属性装饰器定义的.当child.a调用setter方法时,AttributeError会引发a.

在第二个例子中,通过使用property()函数而不是装饰器,一切都按预期工作.

谁能解释为什么行为不同?此外,是的,我知道__init__不需要Child 中的定义.

例1 - 使用 @property

class Parent(object):
    def __init__(self):
        self._a = 'a'
    @property
    def a(self):
        return self._a
    @a.setter
    def a(self, val):
        self._a = val

class Child(Parent):
    def __init__(self):
        super(Child, self).__init__()
    @property
    def a(self):
        return super(Child, self).a
    @a.setter
    def a(self, val):
        val += 'Child'
        super(Child, self).a = val

p = Parent()
c = Child()
print p.a, c.a
p.a = 'b'
c.a = 'b'
print p.a, c.a
Run Code Online (Sandbox Code Playgroud)

示例1 return - 引发属性错误

a a
Traceback (most recent call last):
  File "testsuper.py", line 26, in <module>
    c.a = 'b'
  File "testsuper.py", line 20, in a
    super(Child, self).a = val
AttributeError: 'super' object has no attribute 'a'
Run Code Online (Sandbox Code Playgroud)

例2 - Using property()

class Parent(object):
    def __init__(self):
        self._a = 'a'
    def _get_a(self):
        return self._a
    def _set_a(self, val):
        self._a = val
    a = property(_get_a, _set_a)

class Child(Parent):
    def __init__(self):
        super(Child, self).__init__()
    def _get_a(self):
        return super(Child, self)._get_a()
    def _set_a(self, val):
        val = val+'Child'
        super(Child, self)._set_a(val)
    a = property(_get_a, _set_a)

p = Parent()
c = Child()
print p.a, c.a
p.a = 'b'
c.a = 'b'
print p.a, c.a
Run Code Online (Sandbox Code Playgroud)

示例2返回 - 正确工作

a a
b bChild
Run Code Online (Sandbox Code Playgroud)

小智 7

super()返回一个代理对象,而不是一个超类,它不支持该函数__set__().

你可以在这里看到Python super和设置父类属性的更多细节,在这里http://bugs.python.org/issue14965.