调用变量超类方法

1 投票
2 回答
3241 浏览
提问于 2025-04-16 04:54

我想用一个变量的方法名来调用父类的方法。通常,我会认为下面这两行代码是等价的:

someObj.method()
someObj.__getattribute__( 'method' )()

实际上,我相信这也是我使用第一行时发生的事情。然而,在下面的例子中,第二行却出现了奇怪的问题。

我使用super来构造一个超级对象,并调用父类的方法。直接调用是可以正常工作的,但如果先用__getattribute__来获取这个方法,就会导致一个无限循环,反复调用子类的方法。

看看下面的代码:

class A:
    def example ( self ):
        print( 'example in A' )

class B ( A ):
    def example ( self ):
        print( super( B, self ).example )
        print( super( B, self ).__getattribute__( 'example' ) )
        super( B, self ).example()
        #super( B, self ).__getattribute__( 'example' )()

        print( 'example in B' )

x = B()
x.example()

如果你运行这段代码,一切都会按预期工作,你应该会得到类似这样的输出:

<bound method B.example of <__main__.B object at 0x01CF6C90>>
<bound method B.example of <__main__.B object at 0x01CF6C90>>
example in A
example in B

所以这两种方法,直接访问和通过__getattribute__访问,看起来是一样的。但是,如果你把方法调用替换成注释掉的那一行,你就会遇到递归运行时错误。

为什么会这样呢?更重要的是,当我使用有效的那一行时,如何才能像Python内部那样访问这个方法呢?

编辑

当我以为自己已经尝试了所有方法时,我发现这个方法是有效的:

super.__getattribute__( super( B, self ), 'example' )()

它实际上等同于super( B, self ).example

2 个回答

0

获取一个 B 对象的 example 属性时,会得到一个与 B.example 绑定的副本。如果你调用这个副本,就会出现递归错误。你调用 A.__getattribute__() 这件事并不重要;你依然是在处理一个 B 对象。

5

不要使用 __getattribute__ 来做这个:它的功能可能和你想的不一样。(这是Python内部的一部分,主要用于实现一些特殊的属性访问功能。)

对于普通的属性访问,建议使用 getattr / setattr / delattr 这些内置函数:

self.example           == getattr(self, 'example')
super(B, self).example == getattr(super(B, self), 'example')

(如果你想了解 __getattribute__ 的具体作用,可以看看 描述符指南 和 Python 的 数据模型 参考文档。)

撰写回答