繁体   English   中英

了解Python中的元类

[英]Understanding metaclasses in Python

我试图绕过元类,但我仍然无法真正理解它的概念。

就我所知:

任何类本身就是“类型”类型的实例-因此,“调用”一个类只是在其类上调用方法__call__恰好是类型的__call__ type.__call__的影响正好在以下代码上:

A级:通过b = A()

我在这里知道的步骤顺序是:

1. type.__call__接收类A本身作为其第一个参数。

  1. 它调用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

因此,按照我的理解,这是步骤的顺序:

  1. 由于Spam是MetaOne的实例,因此调用X = Spam()将尝试调用不存在的MetaOne类的__call__方法。

  2. 由于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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM