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