Dynamic use of property() fails

Hrvoje Niksic hniksic at xemacs.org
Tue Apr 15 03:44:43 EDT 2008


andrew cooke <andrew at acooke.org> writes:

> This is my first attempt at new classes and dynamic python, so I am
> probably doing something very stupid...  After reading the how-to for
> descriptors at http://users.rcn.com/python/download/Descriptor.htm I
> decided I would make an object that returns attributes on read, but on
> setting calls an arbitrary function.
>
> My code looks like:
> class ActiveDAO(object):
>     def __init__(self):
>         self.__values__ = {}
>     def add_field(self, name, value, on_change):
>         self.__values__[name] = value
>         def get(self): return self.__values__[name]
>         def set(self, new_value): self.__values__[name] =
> on_change(new_value)
>         def delete(self): raise AttributeError
>         self.__dict__[name] = property(get, set, delete)

As others explained, descriptors are called for descriptors found in
class attributes, not in ones in instance attributes.  Calling them
for the latter would be dangerous because it might accidentally invoke
magic whenever you store the "wrong" kind of object in an instance
attribute.  Also, in many cases (slots), instance property access is
*implemented* using class property descriptors, so calling descriptors
on objects retrieved from the instance would mean that the descriptor
would have to be invoked twice.

However, if you know what you're doing, you can simply customize your
class's __getattribute__ to do what *you* want for your objects.  For
example:

    def __getattribute__(self, name):
        dict = object.__getattribute__(self, '__dict__')  # self.__dict__ would infloop
        if name in dict:
            o = dict[name]
            # call the descriptor even if found in an object in __dict__
            if hasattr(o, '__get__'):
                return o.__get__(self, type(self))
            return o
        return object.__getattribute__(self, name)

With that addition:

>>> dao = ActiveDAO()
>>> dao.add_field('name', 'value', lambda _: None)
>>> dao.name
'value'
>>> dao.__dict__['name']
<property object at 0xb7d53284>



More information about the Python-list mailing list