|
2
|
This recipe provides a LateBindingProperty callable which allows the getter and setter methods associated with the property to be overridden in subclasses.
Sometimes you want the functions that compose a property to be modifiable by subclasses. Using the property builtin, this is not directly supported because the property binds immediately to the function passed to it. So defining another function with the same name in a subclass has no effect:<pre> py> class C(object): ... def getx(self): ... return 'C' ... x = property(getx) ... py> class D(C): ... def getx(self): ... return 'D' ... py> D().x 'C' </pre>This can be worked around by using helper methods to provide late-binding to the method, e.g.:<pre> py> class C(object): ... def getx(self): ... return 'C' ... def _getx(self): ... return self.getx() ... x = property(_getx) ... py> class D(C): ... def getx(self): ... return 'D' ... py> D().x 'D' </pre>but the redundancy has something of a bad code smell. This recipe provides a simple workaround to this problem: rewrite the property descriptor to only look up the function when the property's __get__, __set__ or __del__ is invoked. This allows subclasses to override property getters and setters by simply overriding the appropriate methods:<pre> py> class C(object): ... def getx(self): ... print 'C.getx' ... return self._x ... def setx(self, x): ... print 'C.setx' ... self._x = x ... x = LateBindingProperty('getx', 'setx') ... py> c = C() py> c.x = 1 C.setx py> c.x C.getx 1 py> class D(C): ... def setx(self, x): ... print 'D.setx' ... super(D, self).setx(x) ... py> d = D() py> d.x = 1 D.setx C.setx py> d.x C.getx 1 </pre> |
3 comments
Add a comment
Sign in to comment
Download
Copy to clipboard

Another approach - pass the actual methods, and extract the names from them.
This has the advantages that:
a. You get back an actual property object (with attendant memory savings, performance increases, etc);
b. It's the same syntax as using property(fget, fset, fdel, doc) except for the name;
c. It will fail earlier (when you define the class as opposed to when you use it).
d. It's shorter ;)
e. If you inspect the property you will get back functions with the correct __name__, __doc__, etc.
Reasonable enough. The one disadvantage is that you can't specify that a subclass may implement one of the methods even though the superclass hasn't. Not sure how often this is actually desirable though...
NotImplementedError. The simplest way to deal with this is to have the base class implement the property function to just raise NotImplementedError.