undesired interraction between property and __setattr__

dman dsh8290 at rit.edu
Sat Jan 26 14:25:20 EST 2002


Hi All, I'm back :-).

I'm doing some work with version 2.2 and found that the new property()
feature is just what I'm looking for for part of my work.  The old
__setattr__ is what I want for the rest.  However, I found an
undesired interraction between the two.  This code snippet shows what
happens :

~~~~~~~~~~~~~~~~~~~~
class Struct( object ) : pass

class C( object ) :
    def __init__( self ) :
        self._s = Struct()

    def getx( self ) :
        print "getx!"
        return self._s.the_x
    def setx( self , value ) :
        print "setx!" , value
        self._s.the_x = value
    x = property( getx , setx )

    def __setattr__( self , name , value ) :
        if name == "_s" :
            self.__dict__[name] = value
        else :
            print name , "=>" , value
            setattr( self._s , name , value )

o = C()
o.x = 1
~~~~~~~~~~~~~~~~~~~~

The "Struct" class is just a stand-in to make the example shorter.  In
reality I want to enhance an existing class using composition (hence
the __(get|set)attr__ pair, though get isn't shown here).  For some of
the attributes, however, I want to rename them or add additional
functionality.  For those, "properties" are the right solution.  The
problem is that the setx() method is never called.


Through googling I found this message by Tim Peters :
    http://groups.google.com/groups?hl=en&selm=mailman.1002067383.24001.python-list%40python.org
that explains how the properties thing actually works.  (Thanks Tim.
The documentation I was able to find is a bit parse and magical :-))

This led me to the following "solution" :

~~~~~~~~~~~~~~~~~~~~
class Struct( object ) : pass

class C( object ) :
    def __init__( self ) :
        self._s = Struct()

    def getx( self ) :
        print "getx!"
        return self._s.the_x
    def setx( self , value ) :
        print "setx!" , value
        self._s.the_x = value
    x = property( getx , setx )

    def __setattr__( self , name , value ) :
        if name == "_s" :
            self.__dict__[name] = value
        elif name in self.__class__.__dict__ :
            self.__dict__[ name ] = self.__class__.__dict__[ name ]
            self.__dict__[ name ].__set__( self , value )
        else :
            print name , "=>" , value
            setattr( self._s , name , value )

o = C()
o.x = 1
~~~~~~~~~~~~~~~~~~~~

Notice the extra 'elif' in __setattr__.  I haven't tested it
thoroughly (what happens if a name is duplicated or something?), but
it works in the correct case.

Is this the proper/ideal solution, or is there something I'm missing,
or is this a bug in python?

TIA,
-D

-- 

Q: What is the difference betwee open-source and commercial software?
A: If you have a problem with commercial software you can call a phone
   number and they will tell you it might be solved in a future version.
   For open-source sofware there isn't a phone number to call, but you
   get the solution within a day.





More information about the Python-list mailing list