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 _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com