在动态添加的方法中调用 super 的正确方法是啥?

Posted

技术标签:

【中文标题】在动态添加的方法中调用 super 的正确方法是啥?【英文标题】:What is the corretly way to call super in dynamically added methods?在动态添加的方法中调用 super 的正确方法是什么? 【发布时间】:2021-10-22 23:13:16 【问题描述】:

我定义了一个元类,它将一个名为“test”的方法添加到创建的类中:

class FooMeta(type):
    
    def __new__(mcls, name, bases, attrs):
        def test(self):
            return super().test()
        attrs["test"] = test
        cls = type.__new__(mcls, name, bases, attrs)
        return cls

然后我使用这个元类创建两个类

class A(metaclass=FooMeta):
    
    pass
      

class B(A):
    
    pass

当我跑步时

a = A()
a.test()

super().test() 处引发 TypeError:

super(type, obj): obj must be an instance or subtype of type

这意味着super() 无法正确推断父类。如果我将super 调用更改为

def __new__(mcls, name, bases, attrs):
    def test(self):
        return super(cls, self).test()
    attrs["test"] = test
    cls = type.__new__(mcls, name, bases, attrs)
    return cls

然后引发的错误变为:

AttributeError: 'super' object has no attribute 'test'

预期作为A 的父级没有实现test 方法。


所以我的问题是在动态添加的方法中调用super() 的正确方法是什么?在这种情况下我应该总是写super(cls, self)吗?如果是这样,那就太丑了(对于python3)!

【问题讨论】:

【参考方案1】:

无参数 super() 在 Python 中是 非常 特殊的,因为它会在代码编译期间触发一些行为:Python 创建一个不可见的 __class__ 变量,它是对“物理”class 的引用语句体是否嵌入了 super() 调用(如果在类方法中直接使用 __class__ 变量也会发生这种情况)。

在这种情况下,调用super() 的“物理”类是元类FooMeta 本身,而不是它正在创建的类。

解决方法是使用 super 的版本,它接受 2 个位置参数:它将在其中搜索直接超类的类和实例本身。

在 Python 2 和其他场合可能更喜欢 super 的参数化使用,使用类名本身作为第一个参数是正常的:在运行时,该名称将作为当前模块中的全局变量使用.也就是说,如果class A 将在源文件中静态编码,使用def test(...): 方法,您将在其主体中使用super(A, self).test(...)

然而,尽管类名在定义元类的模块中不能作为变量使用,但您确实需要将对该类的引用作为第一个参数传递给super。由于 (test) 方法接收self 作为对实例的引用,因此其类由self.__class__type(self) 给出。

TL;DR:只需将动态方法中的超级调用更改为:

class FooMeta(type):
    
    def __new__(mcls, name, bases, attrs):
        def test(self):
            return super(type(self), self).test()
        attrs["test"] = test
        cls = type.__new__(mcls, name, bases, attrs)
        return cls

【讨论】:

以上是关于在动态添加的方法中调用 super 的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

将方法添加到调用“super”的动态创建的类

java中paint()的具体用法是啥?

在调用 DataAdapter Fill() 方法后,判断新行是不是添加到 DataTable 的正确方法是啥?

java中的super()是啥

java构造方法中super()的作用是啥?

js中ES6语法的super到底是啥?