[Python-Dev] Python interface to attribute descriptors

Paul F Dubois paul@pfdubois.com
Wed, 13 Nov 2002 14:08:57 -0800


We used to say in the math business that knowing whether something is
true makes it a lot easier to prove. In this case, Guido telling me that
it should work helped me find where I had misread the PEP and I was able
to solve my problem.
For reference for other people, my small example follows. 

Question: how could the descriptor "know" the name "x" if it is created
by a descriptor-creating statement such as x = descriptor_creator(...).
I guess one could do this by making a metaclass that would look for the
descriptors in the class and "poke" the name into them but is there
another way? In the example below I evaded this question by making the
name an argument to positive's constructor.

class positive (object):
    "Attribute that can only be positive."
    def __init__(self, name, default, doc=""):
        self.default = default
        self.__name__ = name
        self.__doc__ = doc

    def __get__ (self, obj, metaobj=None):
        if obj is None:
            return metaobj.__dict__[self.__name__]
        else:
            return getattr(obj, "__" + self.__name__, self.default)

    def __set__ (self, obj, value):
        try:
            v = type(self.default)(value)
            if not (v > 0):
                raise ValueError, "Value not positive."
        except:
            raise ValueError, "Cannot convert to positive %s" %
repr(type(self.default))
        setattr(obj, "__" + self.__name__, v)

class Simple(object) :
    """This class has two attributes, x and y, that must be
     positive floats.
    """
    x = positive("x", 1.0, "x-coordinate")
    y = positive("y", 2.0, "y-coordinate")

    def meth (self):
        return self.x * self.y

s = Simple()
print s.x, s.y, s.meth()
s.x, s.y = (2.,3)
print s.x, s.y, s.meth()
print Simple.x.__doc__
s2 = Simple()
print s2.x, s2.y, s2.meth()
try:
    s.x = -1.0
    raise RuntimeError, "Evaded validation"
except ValueError, e:
    print e

When run this prints:
1.0 2.0 2.0
2.0 3.0 6.0
x-coordinate
1.0 2.0 2.0
Cannot convert to positive <type 'float'>