Newbie: Why doesn't this work

Jeff McNeil jeff at jmcneil.net
Mon Dec 31 13:06:48 EST 2007


I didn't actually answer your question, my apologies!

The reason you're failing is due to your use of the __setattr__ call.
Remember, when you override __setattr__, you need to handle *all* of the
logic behind setting object attributes.  You're only attempting to do so
when handling the 'name' property.   Your __setattr__ method is going to be
called on all assignments, even those internal to the object referencing
self.

For example:

>> class Example(object):
__hidden = 1
nothidden = 2
def __getattr__(self, attr):
print 'getting %s' % attr
if attr == '__hidden':
return self.__hidden
elif attr == 'fakeme':
return 'fakeme+%s' % self.__hidden
def __setattr__(self, attr, value):
print 'setting %s to %s' % (attr, value)
if attr == 'fakeme':
self.__hidden = value


The initial value of 'fakeme' is as defined:

>>> e = Example()
>>> e.fakeme
getting fakeme
'fakeme+1'
>>>

Now, we try to set it to something new using the overridden __setattr__
method:

>>> e.fakeme = 10
setting fakeme to 10
setting _Example__hidden to 10
>>>

Ah! Two calls to __setattr__!  First, our explicit 'e.fakeme = 10' executes
it. Next, it's triggered again recursively when 'self.__hidden = value' is
called.

Your __init__ method itself is triggering a __setattr__ call, so the
corresponding attributes are never actually set:

>>> class Example(object):
def __init__(self, hidden=1):
self.__hidden = hidden
def __getattr__(self, attr):
print 'getting %s' % attr
if attr == '__hidden':
return self.__hidden
elif attr == 'fakeme':
return 'fakeme+%s' % self.__hidden
def __setattr__(self, attr, value):
print 'setting %s to %s' % (attr, value)
if attr == 'fakeme':
self.__hidden = value

>>> e = Example()
setting _Example__hidden to 1
>>> type (e._Example__hidden)
getting _Example__hidden
<type 'NoneType'>


Hope that helps,

Jeff

On 12/31/07, Jeff McNeil <jeff at jmcneil.net> wrote:
>
> Perhaps you'd be better off using a standard property?  Within your Person
> class, you can define a property 'name' to handle what you're trying to do:
>
> Python 2.5 (r25:51918, Sep 19 2006, 08:49:13)
> [GCC 4.0.1 (Apple Computer, Inc. build 5341)] on darwin
> Type "copyright", "credits" or "license()" for more information.
>
>
>     ****************************************************************
>     Personal firewall software may warn about the connection IDLE
>     makes to its subprocess using this computer's internal loopback
>     interface.  This connection is not visible on any external
>     interface and no data is sent to or received from the Internet.
>     ****************************************************************
>
> IDLE 1.2
> >>>
>
>
> >>> class Person(object):
> def __init__(self, fname, lname):
> self.fname = fname
> self.lname = lname
> def get_name(self):
> return '%s %s' % (self.fname, self.lname)
>  def set_name(self, name):
> self.fname, self.lname = name
> name = property(get_name, set_name)
>
>
> >>> p = Person('first', 'last')
> >>> p.name
> 'first last'
> >>> p.name = ('first2', 'last2')
> >>> p.name
> 'first2 last2'
> >>>
>
>
> I found http://users.rcn.com/python/download/Descriptor.htm#properties to
> be a pretty good reference.
>
>
> Thanks,
>
>
> Jeff
>
>
>
> On 12/31/07, ct60 at aol.com <ct60 at aol.com> wrote:
> >
> > 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
> >
> >
> > P = Person()
> >
> > P.name = ("Joe", "Smith")
> >
> > print P.name
> >
> > This fails with the following note:
> >
> > >>>
> > Traceback (most recent call last):
> >   File "C:\Python\testObject.py", line 20, in <module>
> >     print P.name
> >   File "C:\Python\testObject.py", line 8, in __getattr__
> >     return self.__fName + " " + self.__lName
> > TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
> >
> > I don't understand why this fails.  I thought perhaps I need to make
> > the __getattr__ function like this
> >
> >     def __getattr__(self, attr):
> >         if attr == "name":
> >             return self.__fName + " " + self.__lName
> >         elif attr == "__fName":
> >             return self.__fName
> >         elif attr == "__lName":
> >             return self.__lName
> >
> > But that still fails.
> >
> > Can someone please tell me what I am doing wrong?
> >
> > Thansk in advance,
> >
> > Chris (ct60 at aol.com)
> > --
> > http://mail.python.org/mailman/listinfo/python-list
> >
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20071231/ac8f8966/attachment.html>


More information about the Python-list mailing list