Woo*_*ang 4 python oop metaclass super
我定义了一个元类,它将名为“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
Run Code Online (Sandbox Code Playgroud)
然后我使用这个元类创建两个类
class A(metaclass=FooMeta):
pass
class B(A):
pass
Run Code Online (Sandbox Code Playgroud)
当我跑步时
a = A()
a.test()
Run Code Online (Sandbox Code Playgroud)
引发 TypeError 的位置super().test():
super(type, obj): obj must be an instance or subtype of type
Run Code Online (Sandbox Code Playgroud)
这意味着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
Run Code Online (Sandbox Code Playgroud)
那么引发的错误就变成:
AttributeError: 'super' object has no attribute 'test'
Run Code Online (Sandbox Code Playgroud)
这是预期的,因为 的父级A没有实现test方法。
super()所以我的问题是调用动态添加的方法的正确方法是什么?super(cls, self)在这种情况下我应该总是写吗?如果是这样,那就太丑了(对于python3)!
无参数在 Python 中super()非常特殊,因为它在代码编译时本身会触发一些行为: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:只需将动态方法中的 super 调用更改为:
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
Run Code Online (Sandbox Code Playgroud)