Vorticity
Vorticity

Reputation: 4928

Using super() in a property's setter method when using the @property decorator raises an AttributeError

I am a little confused by the behavior when attempting to overwrite a property in a subclass.

The first example sets up two classes, Parent and Child. Parent inherits from object, while Child inherits from Parent. The property a is defined using the property decorator. When child.a's setter method is called, an AttributeError is raised.

In the second example, by using the property() function rather than the decorator, everything works as would be expected.

Can anyone shed some light on why the behavior differs? Also, yes, I know that the __init__ definition in Child is not needed.

Example 1 - Using @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

Example 1 return - Raises an attribute error

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'

Example 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

Example 2 return - Works correctly

a a
b bChild

Upvotes: 19

Views: 7625

Answers (1)

iceout
iceout

Reputation: 438

super() returns a proxy object, not a superclass, and it doesn't support the function __set__().

And you can see more details here Python super and setting parent class property and here http://bugs.python.org/issue14965.

Upvotes: 13

Related Questions