1

我正在尝试在运行时向现有类添加一个新类(使用“type(...)”)。我还试图覆盖那个新类' __getattr__ 以便我可以对不在新类中的属性执行我自己的行为。例如,我有类 foo,我添加类“工具”,我希望 foo.tool.test 做我自己的事情。下面的代码有效,但只是部分有效。如果我显式调用 __getattr__,它可以工作(参见第一个打印),但是当我引用 foo.tool.test 时,我的覆盖 __getattr__ 不会被调用,并且会引发 attrbute 错误。

非常感谢您的帮助。

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 )                         
4

1 回答 1

6

__getattr__Python在实例的 bases 中 寻找特殊方法__dict__,而不是在实例的__dict__.

self.tool是一类。self.tool.test因此,将调用 __getattr__ofself.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 关于这个令人惊讶的陷阱的帖子

为了防止此处出现无限递归的可能性,请使用

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)) 
于 2012-11-30T02:25:26.127 回答