Newbie: Why doesn't this work

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Mon Dec 31 12:36:45 EST 2007


En Mon, 31 Dec 2007 14:56:02 -0200, <ct60 at aol.com> escribi�:

> Hi Python Community:
>
> Despite my new-ness to Python  I have alreadhy been able to do some (I
> think) amazing things.  It is a truly elegant and smart language.
>
> Yet, I can not seem to get a handle on something simple.
>
> I would like to make a class which has private varaiables fName and
> lName.  It should have a property "name" which can get or set a name.
> Something like as follows:
>
> class Person:
>     def __init__(self, fName="", lName=""):
>         self.__fName = fName
>         self.__lName = lName
>
>     def __getattr__(self, attr):
>         if attr == "name":
>             return self.__fName + " " + self.__lName
>
>     def __setattr__(self, attr, value):
>         # this assumes that value is a tuple of first and last name
>         if attr == "name":
>             self.__fName, self.__lName = value

__getattr__ gets called when an attribute lookup fails in the "standard"  
places. Your version, when attr is not "name", does nothing - effectively  
returning None for *any* other attribute.
You should raise an AttributeError instead: add this line after the if:
     raise AttributeError, attr
__setattr__, on the other hand, is called with *any* attempt to set an  
attribute. Your version effectively makes Person "read only"; the only  
attribute you can set is "name". We could fix that, but there are better  
ways. Forget about __getattr__ and __setattr__ and use a property:

class Person(object):
     def __init__(self, fName="", lName=""):
         self._fName = fName
         self._lName = lName

     def getName(self):
         return "%s %s" % (self._fName, self._lName)

     def setName(self, value):
         self._fName, self._lName = value

     name = property(getName, setName)

Note that:
- I've inherited Person from object. Person is then a "new-style" class,  
and only "new-style" classes support properties (and other goodies).

- I've used _fName instead of __fName. The single _ is an indication to  
the outside "warning, this is an implementation detail, don't play with  
it". (Two underscores are (rarely) used when you want to minimize name  
collisions with subclasses.)

- name is now a property, associated to the two functions getName and  
setName. It works the way you want:

py> p = Person("John", "Smith")
py> p.name
'John Smith'
py> p.name = "Tom", "Sawyer"
py> p.name
'Tom Sawyer'

Something I don't like in this design, is that you can't assign the  
property to itself; p.name = p.name fails because the "set" expects a  
tuple and the "get" returns a single string.

-- 
Gabriel Genellina




More information about the Python-list mailing list