我正在尝试在运行时向现有类添加新类 时间(使用“type(...)”)。我也试图覆盖它 新课'__getattr__,这样我就可以做自己的行为了 不属于新类的属性。例如, 我有类foo,我添加类“工具”,我想要foo.tool.test 做我自己的事。下面的代码有效但只是部分代码。如果我显式调用__getattr__,它可以工作(参见第一次打印) 但是当我引用foo.tool.test时,我的被覆盖的__getattr__没有被调用,并且引发了一个属性错误。
非常感谢您的帮助。
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 )
答案 0 :(得分:6)
Python在实例的基础中寻找像__getattr__
这样的特殊方法
__dict__
s,不在实例__dict__
中。
self.tool
是一个班级。因此,self.tool.test
会调用__getattr__
类的self.tool
(object
) - 这不是我们想要发生的事情。
相反,将self.tool
设为一个实例,其类具有__getattr__
:
class Foo(object):
def __init__(self):
self.NameList=[]
# add new class to ourself
toolcls = type('tool', (object,), { '__getattr__' : self.__getattr__, } )
self.tool = toolcls()
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, %s)" % (self.__class__.__name__, attr) )
if( attr in self.NameList ):
return( 99 )
raise AttributeError("--%r object has no attribute %r" % (
type(self).__name__, attr))
foo = Foo()
print( "foo.tool.__getattr__=%d" % foo.tool.__getattr__("test") )
print( "foo.tool.test=%d" % foo.tool.test )
产量
foo.tool.__getattr__=99
foo.tool.test=99
另外,请注意,如果Foo
的实例未定义self.NameList
,则上述代码可能会导致无限递归。请参阅Ned Batchelder's post on this suprising pitfall。
为了防止无限递归,请使用
def __getattr__(self, attr):
# print("__getattr__: (%s, %s)" % (self.__class__.__name__, attr) )
if attr == 'NameList':
raise AttributeError()
if( attr in self.NameList ):
return( 99 )
raise AttributeError("--%r object has no attribute %r" % (
type(self).__name__, attr))