views:

53

answers:

1

I’m currently using the @property decorator to achieve “getters and setters” in a couple of my classes. I wish to be able to inherit these @property methods in a child class.

I have some Python code (specifically, I’m working in py3k) which looks vaguely like so:

class A:
    @property
    def attr(self):
        try:
            return self._attr
        except AttributeError:
            return ''

class B(A):
    @property
    def attr(self):
        return A.attr   # The bit that doesn't work.

    @attr.setter
    def attr(self, value):
        self._attr = value

if __name__ == '__main__':
    b = B()
    print('Before set:', repr(b.attr))
    b.attr = 'abc'
    print(' After set:', repr(b.attr))

I have marked the part that doesn’t work with a comment. I want the base class’ attr getter to be returned. A.attr returns a property object (which is probably very close to what I need!).

Edit:
After receiving the answer below from Ned I thought up what I think is a more elegant solution to this problem.

class A:
    @property
    def attr(self):
        try:
            return self._attr
        except AttributeError:
            return ''

class B(A):        
    @A.attr.setter
    def attr(self, value):
        self._attr = value

if __name__ == '__main__':
    b = B()
    print('Before set:', repr(b.attr))
    b.attr = 'abc'
    print(' After set:', repr(b.attr))

The .setter decorator expects a property object which we can get using @A.attr. This means we do not have to declare the property again in the child class.

(This is the difference between working on a problem at the end of the day vs working on it at the beginning of the day!)

+1  A: 

I think you want:

class B(A):
    @property
    def attr(self):
        return super(B, self).attr()

You mention wanting to return the parent class's getter, but you need to invoke the getter, not return it.

Updated with corrections from the comments:

class B(A):
    @property
    def attr(self):
        return super(B, self).attr
Ned Batchelder
This doesn’t work for me, however, if I call `super().attr` I get the desired effect. Is that a wise thing to do?
casr
Ah, you're right, because the parent's .attr is not available as an invokable getter any more, only as a property. super() is the way to access same-named attributes from parent classes. Why would it be an un-wise thing to do?
Ned Batchelder
Just checking. I didn’t have a reason against. Update your reply to have `super().attr` instead of `super(B, self).attr()` and I’ll mark it as answered :) Thanks for the hint!
casr
You got it! I'll do almost anything for that big green checkmark! :)
Ned Batchelder
Although I did only use `super().attr` and not `super(B, self).attr`. Both seem to work, however.
casr
Learn something new every day: super() with no args is Py3.x only...
Ned Batchelder