I am trying to add a new class to an existing class at run
time (using “type(…)”). I am also trying to override that
new class’ __getattr__ so that I can do my own behavior on
attributes that are not in the new class. For example,
I have class foo, I add class “tool” and I want foo.tool.test
to do something of my own. The code below works but only partly. If I explicitly call __getattr__, it works (see first print)
but when I reference foo.tool.test, my overridden __getattr__ does not get called and an attrbute error is raised.
Your help is greatly appreciated.
class Foo(object):
def __init__(self):
self.NameList=[]
# add new class to ourself
self.tool = type('tool', (object,), {} )
# override new class' __getattr__ with call to ourself
setattr(self.tool, "__getattr__", self.__getattr__ )
# add one well known test name for now
self.NameList.append( "test" )
# should be called by our newly added "tool" object but is only called sometimes...
def __getattr__(self, attr):
# print( "__getattr__: %s" % attr )
if( attr in self.NameList ):
return( 99 )
raise AttributeError("--%r object has no attribute %r" % (type(self).__name__, attr))
foo = Foo()
# access tool class attribute "test" - it should be seen by the override __getattr__
# the following works...
print( "foo.tool.__getattr__=%d" % foo.tool.__getattr__("test") )
# but the following does not - why is this not the same as the line above???
print( "foo.tool.test=%d" % foo.tool.test )
Python looks for special methods like
__getattr__in an instance’s bases__dict__s, not in the instance’s__dict__.self.toolis a class.self.tool.test, therefore, will call the__getattr__ofself.tool‘s class (which isobject) — this is not what we want to happen.Instead, make
self.toolan instance, whose class has a__getattr__:yields
Also, beware that the above code can lead to infinite recursion if an instance of
Foois made withoutself.NameListbeing defined. See Ned Batchelder’s post on this suprising pitfall.To protect against the possibility of infinite recursion here, use