built-in 'property'

Stian Søiland stian at soiland.no
Tue Dec 28 06:58:47 EST 2004


On 2004-12-28 12:05:20, Bob.Cowdery at CGI-Europe.com wrote:

> class NOTOK(object):
>     
>     def __init__(self):
>         self.__x = 0
>         self.x = property(self.getx, self.setx, self.delx, "I'm the 'x'
> property.")
>         
>     def getx(self): return self.__x - 5
>     def setx(self, value): self.__x = value + 10
>     def delx(self): del self.__x

> The OK example has the property and it clearly goes through the get/set
> methods. The NOTOK example creates a property object for x. When I set x it
> creates a new property x which clearly does not invoke the get/set methods.
> Am I doing something stupid here?

Properties must be set on a class level. The "magic" thing about
properties is that property() generates an object with __get__, __set__
and __delete__ methods.

Properties are then defined at the class definition level, as previously
mentioned. The property() function wraps the methods into a property
object, stored as OK.x.

Now, the part where the magic is introduced when accessing attributes.
Remember the normal lookup order for attributes, like obj.x:

1. First, check if this is a local attribute defined in
   obj.__dict__   (like when stored as self.x = something  in __init__)

2. If that fails, go to the class(es) of obj, and look for the attribute
   there, it might be a class attribute.
   
   If this doesn't work, the parent classes are visited, etc.

This applies to both attributes and methods. For methods, something else
is done. When accessing obj.method - the method is wrapped so that the
first parameter self is set automatically to the object obj.   

In new-style classes, this wrapping is performed by the so-called
metaclass, normally the class "type". This is the same metaclass that
takes care of getting attributes from the superclasses if it is not
found. All this is is done in type.__getattribute__  (I think.. haven't
got time to check this up). This method handles attribute lookup for all
methods and attributes in normal classes, like your OK and NOOK. 

In this attribute lookup, if the metaclass finds an object that
implements __get__, the result of calling that method will be returned
instead of the object itself. This is what happens to properties stored
in the class.

If you set the property object in __init__, you are storing the property
object in the objects own attribute namespace, in __dict__. Therefore,
the metaclass will never be involved, as object.__getattribute__ doesn't
handle properties, but just return the objects from __dict__ unchanged.

If you want to support this, for some reason or another, you can
implement the wrapping your self in NOTOK like this:


class NOTOK(object):
    def __getattribute__(self, key):
        obj = object.__getattribute__(key)
        if hasattr(obj, "__get__"):
            return obj.__get__()
        return obj       
    # And similar for __setattr__ and __delattr__

See http://users.rcn.com/python/download/Descriptor.htm for further
details.


-- 
Stian Søiland               Work toward win-win situation. Win-lose
Trondheim, Norway           is where you win and the other lose.
http://soiland.no/          Lose-lose and lose-win are left as an
                            exercise to the reader.  [Limoncelli/Hogan]
                            Og dette er en ekstra linje 



More information about the Python-list mailing list