Skip to main content
 首页 » 编程设计

python之尝试为动态添加的类覆盖 __getattr__ 但仅能正常工作

2025年05月04日19davidwang456

我正在尝试在运行时向现有类添加一个新类 时间(使用“类型(...)”)。我也试图覆盖它 新类' __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))