"property", a very nice new Python 2.2 feature that allows to specify per-attribute access logic, has one drawback: it requires to specify attribute access functions (fget and/or fset) even if direct access to the attribute is needed (the case when f.i. only setting the attribute must be controlled but getting can be performed directly). There is an excellent solution for this problem in systems like Delphi or Borland C++ Builder: a programmer can specify the name of a member variable as a getter and/or setter of a property, in which case corresponding property access goes directly to that member variable. Here is a proposed solution for Python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # "Extended" property class that implements Delphi property logic.
# Its constructor accepts attribute names as well as functions
# for a getter or/and setter parameters thus allowing "direct"
# access to underlying "real" attribute without additional coding.
class xproperty(property):
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
property.__init__(
self,
(isinstance(fget, str) and (lambda obj: getattr(obj, fget))
or fget),
(isinstance(fset, str) and (lambda obj, val: setattr(obj, fset, val))
or fset),
fdel,
doc)
# A simple example of xproperty usage.
# The attribute 's' is converted to lowercase when assigned, but reading
# immediately returns the value of the "real" underlying attribute '_s'
# So, setting s ends up calling __sets; getting s simply returns _s
class Lower(object):
def __init__(self):
self._s = ''
def __sets(self, val):
if isinstance(val, str):
self._s = val.lower()
else:
self._s = val
s = xproperty('_s', __sets)
|
As you can notice, if we used an "ordinary" property in the example above the stub getter function would be required, which purpose is simply to return the value of the underlying attribute. Using xproperty in such cases results in more compact, clear and maintainable code.