__getattr__ and recursion ?
Peter Otten
__peter__ at web.de
Wed Apr 30 06:14:08 EDT 2008
Stef Mientki wrote:
> hello,
>
> I tried to find an easy way to add properties (attributes) to a number
> of different components.
> So I wrote a class, from which all these components are derived.
> By trial and error I created the code below, which now works, but
> there is one thing I don't understand:
> in the line indicated with "<<== 1" I'm not allowed to use
>
> for item in self.extra_getters :
>
> because it will result in an infinite recursion.
> But in the line indicated with "<<== 2" , I am allowed ...
> ... why is this allowed ??
When the instance is created
self.extra_setters = {}
in the __init__() method triggers
self.__setattr__("extra_setters", {})
which executes
for item in self.extra_setters:
# ...
in the __setattr__() method. Because at that point there is no extra_setters
attribute
self.__dict__["extra_setters"]
fails and self.__getattr__("extra_setters") is used as a fallback. Now as
__getattr__() contains a self.extra_getters attribute access and that
attribute doesn't exist either this again triggers
self.__getattr__("extra_getters") -- ad infinitum.
By the way, looping over a dictionary destroys its key advantage, O(1)
lookup. Use
# untested
if attr in self.extra_setters:
self.extra_setters[attr](value)
else:
self.__dict__[attr] = value
and something similar in __getattr__().
Peter
>
> thanks,
> Stef Mientki
>
>
> # ***********************************************************************
> # ***********************************************************************
> class _add_attribs ( object ) :
> def __init__ ( self ) :
> self.extra_setters = {}
> self.extra_getters = {}
>
> def _add_attrib ( self, text, setter = None, getter = None ) :
> if setter :
> self.extra_setters [ text ] = setter
> if getter :
> self.extra_getters [ text ] = getter
>
> # *********************************************************
> # always called instead of the normal mechanism
> # *********************************************************
> def __setattr__ ( self, attr, value ) :
> for item in self.extra_setters :
> if item == attr :
> self.extra_setters [ item ] ( value )
> break
> else :
> self.__dict__[attr] = value
>
> # *********************************************************
> # only called when not found with the normal mechanism
> # *********************************************************
> def __getattr__ ( self, attr ) :
> try :
> for item in self.__dict__['extra_getters'] : <<== 1
> if item == attr :
> return self.extra_getters [ item ] ( ) <<== 2
> except :
> return []
> # ***********************************************************************
More information about the Python-list
mailing list