[Python-Dev] Property inheritance in Python (original) (raw)
Torsten Landschoff torsten at debian.org
Sun Apr 25 17:02:55 CEST 2010
- Previous message: [Python-Dev] Unpickling memory usage problem, and a proposed solution
- Next message: [Python-Dev] Enhanced tracker privileges for "dangerjim" to do triage.
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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
- Previous message: [Python-Dev] Unpickling memory usage problem, and a proposed solution
- Next message: [Python-Dev] Enhanced tracker privileges for "dangerjim" to do triage.
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]