Paul Gilmartin
Paul Gilmartin

Reputation: 72

property.setter and inheritance

I have two classes, BaseClass and Subclass (where Subclass is a subclass of BaseClass). In each of these classes, I have a property 'foo' which I'd like to be able to get and set. The way in which 'foo' is set is independent of the class - it's done the same way in both BaseClass and Subclass. However, the way in which we 'get' the property 'foo' is dependent on the class. I would thus like a way to define my 'setter' on BaseClass and have it inherit to Subclass in such a way that it's compatible with the class-dependent implementations of the 'getter' in both Subclass and BaseClass.

My first instinct was to use python @property and @property.setter. I quickly ran into issues:

class BaseClass(object):
    def __init__(self):
        self._foo = None

    @property
    def foo(self):
        print 'BaseClass'

    @foo.setter       
    def foo(self, val):
        self._foo = val


class Subclass(BaseClass):

    @property
    def foo(self):
        print 'Subclass'

My naive hope was that the foo.setter would be inherited into Subclass and that it would be compatible with the Subclass implementation of the foo property. However:

b = BaseClass()
s = Subclass()
b.foo
BaseClass
s.foo
Subclass
b.foo = 'BaseClass!'
s.foo = 'Subclass!'
Traceback (most recent call last):
 File "<input>", line 1, in <module>
AttributeError: can't set attribute

I believe what is happening here is that the '@foo.setter' is being bound to the BaseClass namespace at compile time, and thus is not available to Subclass (although I could be wrong on this point).

Can anyone tell me a neat way of achieving what I want here? It doesn't necessarily need to use python property builtin, but that would be nice.

Upvotes: 0

Views: 851

Answers (2)

Dylan Black
Dylan Black

Reputation: 131

There are some interesting things going on here. BaseClass.foo is an object, and the lines

@foo.setter       
def foo(self, val):
    self._foo = val

return a modified copy of that object.

In the SubClass, you are redefining this object by recreating the property and so you will need to write a new setter or follow Aran-Fey’s answer.

I found a similar question that might also help with understanding this idea.

Upvotes: 1

Aran-Fey
Aran-Fey

Reputation: 43136

You can use @BaseClass.foo.getter to create a copy of the property with a different getter:

class Subclass(BaseClass):
    @BaseClass.foo.getter
    def foo(self):
        print('Subclass')

See the property documentation for details.

Upvotes: 1

Related Questions