Before you rush to the mall and get yourself some expensive descriptors, note that Python ships with some very useful ones that can be found by simply looking in the box.
Example 1.7. Built-in descriptors
class HidesA(object):
def getA(self):
return self.b - 1
def setA(self, val):
self.b = val + 1
def delA(self):
del self.b
a = property(getA, setA, delA, "docstring")
def clsMethod(cls):
return "You called class %s" % cls
clsMethod = classmethod(clsMethod)
def stcMethod():
return "Unbindable!"
stcMethod = staticmethod(stcMethod)
As we saw earlier, Python functions are descriptors too. They weren't descriptors in earlier versions of Python (as there were no descriptors at all), but now they fit nicely into a more generic mechanism.
A property is always a data-descriptor, but not all arguments are required when defining it.
Example 1.8. More on properties
class VariousProperties(object):
def getP(self):
pass
def setP(self, val):
pass
def delP(self):
pass
allOk = property(getP, setP, delP)
unDeletable = property(getP, setP)
readOnly = property(getP)
The getter and setter functions need not be defined in the class itself, any function can be used. In any case, the functions will be called with the instance as the first argument. Note that where the functions are passed to the property constructor above, they are not bound functions anyway.
Another useful observation would be to note that subtyping the
class and redefining the getter (or setter) functions is not going to
change the property. The property object is holding
on to the actual functions provided. When kicked, it is
going to say "Hey, I'm holding this function I was given, I'll just
call this and return the result.", and not "Hmm, let me look up the
current class for a method called 'getA' and
then use that". If that is what one wants, then defining a new
descriptor would be useful. How would it work? Let's say it is
initialized with a string (i.e. the name of the method to call). On
activation, it does a getattr() for the method name
on the type, and use the method found. Simple!
Classmethods and staticmethods are non-data descriptors, and so can be
hidden if an attribute with the same name is set
directly on the instance. If you are rolling your own descriptor (and
not using properties), it can be made read-only by giving it a
__set__() method but raising
AttributeError in the method. This is how a
property behaves when it does not have a setter function.