[英]Understanding metaclasses in Python
我试图绕过元类,但我仍然无法真正理解它的概念。
就我所知:
任何类本身就是“类型”类型的实例-因此,“调用”一个类只是在其类上调用方法__call__
恰好是类型的__call__
。 type.__call__
的影响正好在以下代码上:
A级:通过b = A()
我在这里知道的步骤顺序是:
1. type.__call__
接收类A本身作为其第一个参数。
A.__new__
在伪代码中,我们可以将instance = A.__new__(cls)
作为运行内容编写。 3.返回“ A”类的实例
4,然后在实例上调用__init__
( instance.__init__()
)...并返回该实例的return instance
但是现在考虑以下代码:
class MetaOne(type):
def __new__(meta, classname, supers, classdict):
print('In MetaOne.new:', meta, classname, supers, classdict, sep='\n...')
return type.__new__(meta, classname, supers, classdict)
class Eggs:
pass
print('making class')
class Spam(Eggs, metaclass=MetaOne):
data = 1
def meth(self, arg):
return self.data + arg
print('making instance')
X = Spam()
print('data:', X.data, X.meth(2))
该脚本的输出如下:
making class
In MetaOne.new:
...<class '__main__.MetaOne'>
...Spam
...(<class '__main__.Eggs'>,)
...{'__qualname__': 'Spam', '__module__': '__main__', 'meth': <function Spam.met
h at 0x00000000010C1D08>, 'data': 1}
making instance
data: 1 3
因此,按照我的理解,这是步骤的顺序:
由于Spam是MetaOne的实例,因此调用X = Spam()
将尝试调用不存在的MetaOne类的__call__
方法。
由于MetaOne从类型继承,因此它将使用Spam
作为第一个参数来调用类型类的__call__
方法。
之后,该调用会到达MetaOne类的__new__
方法中,但它应包含Spam
作为第一个参数。
MetaOne类的meta
参数从何而来。
请帮助我理解。
由于Spam是MetaOne的实例,因此调用X = Spam()将尝试调用不存在的MetaOne类的
__call__
方法。
这是你的困惑soruce -的__call__
(或__new__
和__init__
元类的)当您创建类的实例一般不叫。
而且,由于没有用于MetaOne
__call__
方法,所以适用通常的继承规则:使用MetaOne的超类上的__call__
方法(它是type.__call__
)。
当执行类主体本身时,将调用元类的__new__
和__init__
方法(如您在示例中所看到的,元类的__new__
中的“打印”显示在“生成实例”文本之前)。
当创建的实例Span
本身的元类方法__new__
和__init__
不叫-元类__call__
被称为-这是执行类的(跨度的) __new__
和__init__
。 换句话说:元类__call__
负责调用“普通”类的__new__
和__init__
。
因为MetaOne从类型继承,所以它将使用垃圾邮件作为第一个参数来调用类型类的调用方法。
确实如此,但是您没有打印语句来“查看”这种情况:
class MyMeta(type):
def __new__(metacls, name, bases, namespace):
print("At meta __new__")
return super().__new__(metacls, name, bases, namespace)
def __call__(cls, *args, **kwd):
print ("at meta __call__")
return super().__call__(*args, **kwd)
def Egg(metaclass=MyMeta):
def __new__(cls):
print("at class __new__")
如果我将其粘贴在非活动控制台上,此时它将打印:
At meta __new__
然后,进行交互式会话:
In [4]: fried = Egg()
at meta __call__
at class __new__
而且,令人费解的是:“类型是类型自己的元类”:意味着当新的(非元)类体被使用时, type
的__call__
还负责在元类本身上运行__new__
和__init__
方法。执行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.