[Python-Dev] Property inheritance in Python (original) (raw)

Torsten Landschoff torsten at debian.org
Sun Apr 25 17:02:55 CEST 2010


Hi Python experts.

[It should be obvious, but you can run the code in this message via python -m doctest body.txt if you saved it as body.txt]

In an application I develop on I want to use properties instead of the getter/setter paradigm. I ran into a problem overriding a property in a subclass. While I know how to do it with current Python, I propose changing the behaviour to be more consistent.

For presentation, here is a stupid example using getters and setters:

class BaseGetterSetter(object): ... def get_p(self): ... return self._p ... def set_p(self, value): ... self._p = value class DerivedGetterSetter(BaseGetterSetter): ... def get_p(self): ... return super(DerivedGetterSetter, self).get_p() * 2 ... def set_p(self, value): ... super(DerivedGetterSetter, self).set_p(value / 2) d = DerivedGetterSetter() d.set_p(42) d._p 21 d.get_p() 42

When translating this to use properties, I would come up with something like this:

class BaseProp(object): ... @property ... def p(self): ... return self._p ... @p.setter ... def p(self, value): ... self._p = value class DerivedProp(BaseProp): ... @property ... def p(self): ... return super(DerivedProp, self).p * 2 ... @p.setter ... def p(self, value): ... super(DerivedProp, self).p = value / 2 d = DerivedProp() d._p = 21 d.p 42 d.p = 50 Traceback (most recent call last): ... AttributeError: 'super' object has no attribute 'p'

As can be seen, using super like in the getter/setter approach above works for fget but not for fset. Support for using the getter via super() was added for Python 2.3 according to http://mail.python.org/pipermail/python-dev/2003-April/034702.html

I think it would be more consistent to be able to access the set call via super() as well.

Working around

The problematic code boils down to

super(DerivedProp, d).p = 1 Traceback (most recent call last): ... AttributeError: 'super' object has no attribute 'p'

which can be worked around like this:

BaseProp.p.fset(d, 25) BaseProp.p.set(d, 10)

I'd rather use the method resolution order computed by Python so that mixin classes can extend the behaviour of properties. For that, one can extend super:

class duper(super): ... def setattr(self, name, value): ... mro = self.self_class.mro ... for pos in xrange(len(mro)): ... if mro[pos] == self.thisclass: ... break ... for pos in xrange(pos+1, len(mro)): ... tmp = mro[pos] ... if isinstance(tmp, type) and name in tmp.dict: ... desc = tmp.dict[name] ... desc.set(self.self, value) ... return duper(DerivedProp, d).p = 100 d.p 200

Extending super

I wrote a test case for the super() behaviour as I would like it to be and implemented the setattr of duper above into super's C implementation. The code is not of production quality and there are some open questions. But I figured that I'd rather ask for opinions before spending even more time on this.

The code is available on launchpad at this URL: https://code.launchpad.net/~torsten/python/descr-set-via-super

What do you think, do you agree with my understanding or am I completely wrong?

Hoping for some insightful comments,

Torsten



More information about the Python-Dev mailing list