Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 调用super()时,元类如何处理MRO列表?_Python_Super_Metaclass_Method Resolution Order - Fatal编程技术网

Python 调用super()时,元类如何处理MRO列表?

Python 调用super()时,元类如何处理MRO列表?,python,super,metaclass,method-resolution-order,Python,Super,Metaclass,Method Resolution Order,我真的被下面的代码示例弄糊涂了: class Meta_1(type): def __call__(cls, *a, **kw): # line 1 print("entering Meta_1.__call__()") print(cls) # line 4 print(cls.mro()) # line 5

我真的被下面的代码示例弄糊涂了:

class Meta_1(type):
    def __call__(cls, *a, **kw):             # line 1
        print("entering Meta_1.__call__()")  

        print(cls)                           # line 4
        print(cls.mro())                     # line 5
        print(super(Meta_1, cls).__self__)   # line 6

        rv = super(Meta_1, cls).__call__(*a, **kw)  # line 7
        print("exiting Meta_1.__call__()")
        return rv


class Car(object, metaclass=Meta_1):

    def __new__(cls, *a, **kw):
        print("Car.__new__()")
        rv = super(Car, cls).__new__(cls, *a, **kw)
        return rv

    def __init__(self, *a, **kw):
        print("Car.__init__()")
        super(Car,self).__init__(*a, **kw)

if __name__ == '__main__':

    c = Car()
此代码的打印消息为:

entering Meta_1.__call__()
<class '__main__.Car'>                      # line 4
[<class '__main__.Car'>, <class 'object'>]  # line 5
<class '__main__.Car'>                      # line 6
Car.__new__()
Car.__init__()
exiting Meta_1.__call__()
输入Meta\u 1.\u调用
#第4行
[,]#第5行
#第6行
汽车。新的
汽车。初始
正在退出Meta_1.__调用__()
结果显示,4号线的
cls
Car
类,其MRO列表为:
[,]

但是,第6行显示
super(Meta_1,cls)。\uuuuu self\uuuuu
也是
Car

我真的很困惑:

  • 在第7行中,似乎
    super(Meta\u 1,cls).\u调用
    最终导致
    type.\u调用
    。 但是,据我所知,
    super(arg1,arg2)
    将研究第二个输入参数的MRO以找到第一个输入参数,并将下一个类返回给它。但是在我的代码的第6行和第7行中,第二个参数(
    Car
    )的MRO不包含第一个输入参数(
    Meta\u 1
    ),您无法在
    Car
    的MRO中找到
    Meta\u 1
    。那么为什么
    super(Meta\u 1,cos)
    会让我们调用
    type.\u调用\u

    二,。如果
    super(Meta\u 1,cls)。\uuu self\uuuuu
    Car
    类,那么第7行表示调用的是
    Car
    ?但是打电话给
    汽车
    班首先把我们带到了1号线,对吗?这不是一个循环吗

    您混淆了一些概念。第一个问题是将元类与类继承层次结构混淆

    这两件事都是正交的——查看
    Car
    的mro将向您显示该类的继承树,而这并不包括元类。换句话说,无论如何,没有
    Meta_1
    不应该位于MRO(或继承树)中

    元类是类的类型——也就是说,它具有创建类对象本身的模板和方法。因此,它有“机制”来构建类MRO本身,并调用类“
    \uuuuu new\uuuu
    \uuuu init\uuuu
    (和
    \uuuu init\u子类\uuuuu
    ,并初始化调用其
    \uu集\uu name>的描述符)

    因此,调用一个类对象,就像调用Python中的任何实例一样,将在它的class
    \uuuu call\uuu
    方法中运行代码。在类的情况下,“调用”类是创建新实例的方式,而元类“
    \uuuuu call\uuu
    ”就是这样做的

    您误解的另一件事是
    super()
    对象
    Super()
    实际上不是超类,也不是超类的实例-而是一个代理对象,它将任何属性检索或方法调用传递到适当超类上的方法和属性。作为
    super()
    用作代理的机制的一部分,是将实例作为其自身的
    \uuuuuuuuuuuuuuuuuuuuuuu属性调用。换句话说,
    \uuu self\uuu
    属性是
    super()
    调用返回的(代理)对象上的普通属性-它从第二个参数中选取,或者在Python3中自动执行—当
    super
    对象用作代理时,它会在内部使用,就像它正在访问该实例的“超类”上的属性或方法一样。(在
    \uuuu self\uuu
    中注释的实例)

    在元类内部使用
    super()
    时,代理的类是元类的超类,即
    类型
    ,而不是Car的超类,
    对象

    关于你的第二个问题:

  • 如果
    super(Meta\u 1,cls)。\uuuuuu self\uuuu
    是汽车类,那么第7行表示正在调用的是汽车的
    \uu调用\uuu
    ?但是给车打电话 第一节课把我们带到了一号线,对吗?那不是个好主意吗 环路

  • 如上所述,元类的
    super()
    调用将调用
    type.\uu调用,它将获得类
    Car
    作为其
    cls
    参数。该方法将依次运行
    Car.\uuuuu new.\uuuu
    Car.\uuuu init.\uuuu
    作为实例化类的正常过程。

    重要的是要注意
    super
    的每个参数都使用了哪些值。
    super
    的主要目的是根据某种方法解析顺序(MRO)执行属性查找。第二个参数决定使用哪个MRO;第一个决定从哪里开始寻找

    MRO始终由类定义;在对实例执行方法解析时,我们使用该实例所属类的MRO

    在课堂上

    class Meta_1(type):
        def __call__(cls, *a, **kw):             # line 1
            print("entering Meta_1.__call__()")  
    
            print(cls)                           # line 4
            print(cls.mro())                     # line 5
            print(super(Meta_1, cls).__self__)   # line 6
    
            rv = super(Meta_1, cls).__call__(*a, **kw)  # line 7
            print("exiting Meta_1.__call__()")
            return rv
    
    我们看到了
    super
    的两种用法。两者的论点相同
    cls
    是作为第一个参数传递给
    Meta\u 1.\u\u调用\u\u
    的某个对象。这意味着我们将使用
    type(cls)
    提供的MRO,并使用在
    Meta\u 1
    之后找到的第一个类来提供所需的方法。(在第一个调用中,
    \uuuu self\uuu
    是代理对象本身的属性,而不是其代理
    super
    返回的类的属性或方法。)

    运行代码时,您会看到
    cls
    绑定到
    Car
    type对象。这是因为
    Car()
    是由
    type(Car)实现的;由于
    Car
    使用
    Meta\u 1
    作为其元类,
    type(Car)
    Meta\u 1

    cls.mro()

    Meta_1
    本身的MRO可以通过

    >>> Meta_1.mro(Meta_1)
    [<class '__main__.Meta_1'>, <class 'type'>, <class 'object'>]
    
    >>Meta_1.mro(Meta_1)
    [, ]
    
    mro
    type
    类的实例方法,因此需要
    type
    的看似冗余的实例作为参数。请记住