Re: built-in 'property'

Discussion in 'Python' started by Stian =?iso-8859-1?Q?S=F8iland?=, Dec 28, 2004.

  1. On 2004-12-28 12:05:20, 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
    Stian =?iso-8859-1?Q?S=F8iland?=, Dec 28, 2004
    #1
    1. Advertising

  2. Stian Søiland wrote:
    > On 2004-12-28 12:05:20, 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


    I seem to be missing some of the messages on this thread, but while
    we're talking about properties, it's probably instructive to remind
    people that the functions passed to the property function are not
    redefinable in subclasses:

    py> class D(C):
    .... def getx(self):
    .... return 42
    ....
    py> D(5).x
    5
    py> class C(object):
    .... def getx(self):
    .... return 1
    .... x = property(getx)
    ....
    py> class D(C):
    .... def getx(self):
    .... return 42
    ....
    py> C().x
    1
    py> D().x
    1

    Note that even though I redefined getx in class D, the 'x' property is
    still using the function C.getx that was passed into it.

    For this reason, I usually suggest declaring properties like[1]:

    py> class E(object):
    .... def x():
    .... def get(self):
    .... return float(self._x)
    .... def set(self, x):
    .... self._x = x**2
    .... return dict(fget=get, fset=set)
    .... x = property(**x())
    .... def __init__(self, x):
    .... self._x = x
    ....
    py> e = E(42)
    py> e.x
    42.0
    py> e.x = 3
    py> e.x
    9.0

    Note that by using the x = property(**x()) idiom, I don't pollute my
    class namespace with get/set/del methods that aren't really useful to
    instances of the class. It also makes it clear to subclasses that if
    they want different behavior from the x property that they'll need to
    redefine the entire property, not just a get/set/del method.

    Steve

    [1] Thanks to whoever originally suggested this! Sorry, I've forgotten
    who...
    Steven Bethard, Dec 28, 2004
    #2
    1. Advertising

  3. Steven Bethard wrote:
    > I seem to be missing some of the messages on this thread, but while
    > we're talking about properties, it's probably instructive to remind
    > people that the functions passed to the property function are not
    > redefinable in subclasses:
    >
    > py> class D(C):
    > ... def getx(self):
    > ... return 42
    > ...
    > py> D(5).x
    > 5


    Oops, sorry! Bad copy-paste! No biscuit! Ignore the code above here.
    Important code is below:

    > py> class C(object):
    > ... def getx(self):
    > ... return 1
    > ... x = property(getx)
    > ...
    > py> class D(C):
    > ... def getx(self):
    > ... return 42
    > ...
    > py> C().x
    > 1
    > py> D().x
    > 1


    Steve
    Steven Bethard, Dec 28, 2004
    #3
  4. Steven Bethard <> wrote:

    > For this reason, I usually suggest declaring properties like[1]:
    >
    > py> class E(object):
    > ... def x():
    > ... def get(self):
    > ... return float(self._x)
    > ... def set(self, x):
    > ... self._x = x**2
    > ... return dict(fget=get, fset=set)
    > ... x = property(**x())
    > ... def __init__(self, x):
    > ... self._x = x
    > ...
    > py> e = E(42)
    > py> e.x
    > 42.0
    > py> e.x = 3
    > py> e.x
    > 9.0
    >
    > Note that by using the x = property(**x()) idiom, I don't pollute my
    > class namespace with get/set/del methods that aren't really useful to
    > instances of the class. It also makes it clear to subclasses that if
    > they want different behavior from the x property that they'll need to
    > redefine the entire property, not just a get/set/del method.
    >
    > Steve
    >
    > [1] Thanks to whoever originally suggested this! Sorry, I've forgotten
    > who...


    In the Cookbook 2nd ed, I credited Sean Ross, the author of the CB
    recipe proposing this (with credit also to David Niegard and Holger
    Krekel for important comments whose contents I merged into the recipe).

    Of course there are several possible variations, such as
    return locals()
    instead of return dict(&c)...


    Alex
    Alex Martelli, Dec 29, 2004
    #4
  5. Stian =?iso-8859-1?Q?S=F8iland?=

    Sean Ross Guest

    "Steven Bethard" <> wrote in message
    news:4hhAd.650831$D%.387759@attbi_s51...
    [snip]
    > For this reason, I usually suggest declaring properties like[1]:
    >
    > py> class E(object):
    > ... def x():
    > ... def get(self):
    > ... return float(self._x)
    > ... def set(self, x):
    > ... self._x = x**2
    > ... return dict(fget=get, fset=set)
    > ... x = property(**x())
    > ... def __init__(self, x):
    > ... self._x = x
    > ...

    [snip]
    >
    > [1] Thanks to whoever originally suggested this! Sorry, I've forgotten
    > who...


    Hello.

    As Alex mentioned, I'm the author of the "tidy property idiom" recipe. I
    stumbled across the idea back in June of 2003, when there were ongoing
    discussions about property syntax and, in particular, thunks. I've
    discovered that Greg Ewing had a similar idea 6 months earlier [1], though I
    wasn't aware of that at the time. I'll note that it is possible to change
    the built-in property (in a backward compatible manner) to be used as a
    decorator for this idiom, to redefine parts of properties in sub-classes,
    and to provide default get/set/del methods. That being said, while I
    appreciate that there are people who like this recipe (and others who
    don't), I think it's important to point out that this is *not* the
    recommended property idiom. Moreover, Guido doesn't like it and he would
    prefer that it not become the standard [2][3].

    Sean


    [1] http://mail.python.org/pipermail/python-dev/2003-January/032611.html
    [2] http://mail.python.org/pipermail/python-dev/2003-January/032630.html
    [3] http://mail.python.org/pipermail/python-dev/2004-January/042206.html
    Sean Ross, Dec 30, 2004
    #5
  6. Sean Ross wrote:
    > I'll note that it is possible to change
    > the built-in property (in a backward compatible manner) to be used as a
    > decorator for this idiom, to redefine parts of properties in sub-classes,
    > and to provide default get/set/del methods.


    Is there a recipe or blog or something somewhere that talks about
    redfining property in these ways? I'd be interested to read about it...

    Steve
    Steven Bethard, Dec 31, 2004
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Eric Newton
    Replies:
    3
    Views:
    9,377
    Brock Allen
    Apr 4, 2005
  2. Joshua Beall
    Replies:
    1
    Views:
    420
    Bertilo Wennergren
    Dec 10, 2003
  3. Noozer
    Replies:
    10
    Views:
    2,068
    Mitja
    Oct 13, 2004
  4. Nathan Sokalski
    Replies:
    1
    Views:
    1,105
    =?Utf-8?B?SmVk?=
    Apr 29, 2006
  5. TS
    Replies:
    3
    Views:
    2,467
Loading...

Share This Page