我正在尝试在运行时向现有类添加一个新类 时间(使用“类型(...)”)。我也试图覆盖它 新类' __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 )
请您参考如下方法:
Python 在实例的基类中寻找特殊方法,如 __getattr__ __dict__,不在实例的 __dict__ 中。
self.tool 是一个类。因此,self.tool.test 将调用 self.tool 类的 __getattr__(即 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
此外,请注意,如果在未定义 self.NameList 的情况下生成 Foo 实例,则上述代码可能会导致无限递归。参见 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))
