problems with __getattr__ & __setattr__

Tim Evans tre17 at student.canterbury.ac.nz
Wed Nov 17 03:37:01 CET 1999


ScherBi at BAM.com writes:

> I am having trouble using __getattr__ and __setattr__ in some classes.  I've
> boiled it down to the code below.
> It dumps core under 1.5.2 on Linux or WinNT.
> 
> I think maybe it's looping, if so, how does one go about doing this? 
> (I'm assuming it's clear enough what I'm trying to do.)
> 
> If I comment out the __gettattr__ operation, it doesn't dump core.  Instead
> I get an AttributeError: eggs raised at the 'self.eggs[key] = value' call in
> __setattr__.  This is what leads me to belive there's something circular
> going on here.
> 
> 
> Thanks,
>  Bill
> 
> --------------------------------------------
> class spam:
> 
>     def __init__(self):
>         self.eggs = {}
>     
>     def __getattr__(self, key):
>         try:
>             return self.eggs[key]
>         except:
>             raise
>         
>     def __setattr__(self, key, value):
>         try:
>             self.eggs[key] = value
>             return 0
>         except:
>             raise
> 
> if __name__ == '__main__':
> 
>     s = spam()
>     print 'instance of spam created.' 
> -----------------------------------------------

I think I see the problem here.  In __init__ you try to set an
attribute (self.eggs = {}), which will cause __setattr__ to be called.

In __setattr__ you get the eggs attribute, which does not exist, so
the attribute access is passed to __getattr__.

In __getattr__ you access the eggs attribute again, which as it does
not exist will again be passed to __getattr__, causing an infinite
loop.

To demonstrate this add a print statement at the start of each method
that prints the name of the method.  The result is:

-----------------------------
% python broken.py
__init__
__setattr__
__getattr__
__getattr__
__getattr__
__getattr__
__getattr__
__getattr__
__getattr__
...
zsh: segmentation fault  python broken.py
-----------------------------

To solve this problem I would recommend not using __getattr__ and
__setattr__ unless you really need it.  If you don't want to use
s.eggs['foo'] then you could define __setitem__ and __getitem__ to
shorten this to s['foo']

--
Tim Evans




More information about the Python-list mailing list