This recipe provides a function that will automate simple property creation, while allowing its users to provide specific fget/fset/fdel methods.
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | import sys
def attribute(attrname, permit='rwd', fget=None, fset=None, fdel=None, doc=''):
"""returns a property associated with 'attrname'.
By default, a simple property with get, set, and delete methods
will be created. Optionally, specific get/set/del methods may be
supplied. You can also choose to omit the creation of one or more
of the default get/set/del methods via the 'permit' flag:
'r': readable, 'w':writable, 'd':deletable
So, if you want a property that is readable and deletable, but not
writable, use "permit='rd'".
"""
if _isprivate(attrname):
attrname = _mangle(_get_classname(), attrname)
if 'r' in permit and fget is None:
fget = lambda self: getattr(self, attrname)
if 'w' in permit and fset is None:
fset = lambda self, value: setattr(self, attrname, value)
if 'd' in permit and fdel is None:
fdel = lambda self: delattr(self, attrname)
return property(fget, fset, fdel, doc)
def _isprivate(attrname):
return attrname.startswith("__") and not attrname.endswith("__")
def _mangle(classname, attrname):
'''mangles name according to python name-mangling
conventions for private variables'''
return "_%s%s" % (classname, attrname)
def _get_classname():
"returns the calling class' name"
frame = sys._getframe(2)
classname = frame.f_code.co_name
return classname
# example
if __name__ == "__main__":
class C(object):
a = attribute('_a', fget=lambda self: self._a*2)
def __init__(self):
self._a = "A"
c = C()
print c.a # uses a.fget, user supplied
c.a = "AA" # uses a.fset, provided by default
print c.a
|
This recipe may be useful if you want to make a property where at least one of fget, fset, or fdel is non-trivial but you don't want to bother providing the other trivial implementations. By trivial implementations for fget, fset, fdel, I mean:
fget = lambda self: getattr(self, attrname) fset = lambda self, value: setattr(self, attrname, value) fdel = lambda self: delattr(self, attrname)
This recipe provides the trivial implementations for fget/fset/fdel by default. Users can substitute specific implementations for, or they can omit, any of these methods.
If you only intend to create simple properties, my other recipe (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/157768) should suffice. But, if you want to mix simple property creation with specific, this recipe may be of some use.
Here's an alternative implementation of attribute() which does not require that self.attrname be initialized in __init__():
def attribute2(attrname, default=None, permit='rwd',
if __name__ == "__main__":