当调用super()时,元类如何与MRO列表一起工作?

6 浏览
0 Comments

当调用super()时,元类如何与MRO列表一起工作?

以下是对上述代码示例的翻译:\n我对以下代码示例感到非常困惑:\n

class Meta_1(type):
    def __call__(cls, *a, **kw):             # 第1行
        print("进入 Meta_1.__call__()")  
        print(cls)                           # 第4行
        print(cls.mro())                     # 第5行
        print(super(Meta_1, cls).__self__)   # 第6行
        rv = super(Meta_1, cls).__call__(*a, **kw)  # 第7行
        print("退出 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()

\n此代码的打印信息为:\n

进入 Meta_1.__call__()
                      # 第4行
[, ]  # 第5行
                      # 第6行
Car.__new__()
Car.__init__()
退出 Meta_1.__call__()

\n结果显示,第4行的clsCar类,并且它的MRO列表为:
\n[, ]
\n然而,第6行显示super(Meta_1, cls).__self__也是Car类。\n我真的很困惑:\n

    \n

  1. 在第7行中,似乎super(Meta_1, cls).__call__(*a, **kw)最终导致调用了type.__call__。\n但是,据我所知,super(arg1, arg2)会查找第二个输入参数的MRO以找到第一个输入参数,并返回它的下一个类。\n但在我的代码的第6行和第7行中,第2个参数(Car)的MRO中并不包含第1个输入参数(Meta_1),你无法在Car的MRO中找到Meta_1。那么为什么super(Meta_1, cos)会让我们调用type.__call__
  2. \n

\n2. 如果super(Meta_1, cls).__self__Car类,那么第7行意味着正在调用Car__call__?但是调用Car类会导致我们进入第1行,对吗?这不会造成循环吗?

0
0 Comments

元类是Python中一种特殊的类,用于创建其他类。它的主要作用是控制类的创建和初始化过程。当使用超类方法`super()`时,元类会与MRO列表(Method Resolution Order,方法解析顺序)一起工作。

在上述引用中,原作者解释了`super()`如何使用元类和MRO列表。`super()`会使用当前类(`cls`)来查找MRO列表,但并不是直接使用`cls.__mro__`来查找元类。相反,它会查找`cls`的类(也就是元类),然后从该类中查找MRO列表。

这意味着,当我们在一个类中调用`super()`时,它会首先查找该类的元类,然后再查找元类的MRO列表。这种行为与直接调用`cls.__mro__`不同,因为`cls`的MRO列表是与`cls`所继承的类相关的,而不是与元类相关的。

解决这个问题的方法是使用`super()`来调用父类的方法,而不是直接使用`cls.__mro__`。这样,`super()`会自动查找正确的MRO列表,以确保方法顺序的正确性。

总结起来,当我们在使用元类时,并在类中使用`super()`调用父类的方法时,我们需要意识到`super()`实际上是通过查找元类和MRO列表来确定方法的调用顺序。我们应该避免直接使用`cls.__mro__`,而是使用`super()`来确保正确的方法解析顺序。

0
0 Comments

在这段内容中,提到了在使用super()函数时,Metaclass是如何与MRO列表相结合的。根据内容,问题的出现原因是因为在使用super()函数时,需要注意每个参数所使用的值。super()函数的主要目的是根据某个方法解析顺序(MRO)进行属性查找。第二个参数确定要使用哪个MRO,而第一个参数确定从哪里开始查找。

在这段内容中,给出了一个名为Meta_1的类的示例。在这个类中,有两个使用super()函数的地方,它们都使用相同的参数。cls是作为第一个参数传递给Meta_1.__call__方法的某个对象。这意味着我们将使用type(cls)提供的MRO,并且我们将使用在Meta_1之后找到的第一个提供所需方法的类。

当运行代码时,可以看到cls绑定到了Car类型的对象。这是因为Car()是由type(Car).__call__()实现的;由于Car使用Meta_1作为其元类,所以type(Car)是Meta_1。

根据给出的内容,可以得出解决方法:在使用super()函数时,需要注意每个参数所使用的值。第一个参数决定从哪里开始查找,第二个参数决定要使用的MRO。如果想使用type(cls)的MRO,可以将type(cls)作为第二个参数传递给super()函数。

,当调用super()函数时,Metaclass是根据MRO列表来工作的。通过指定参数,可以确定从哪里开始查找以及使用哪个MRO。这样可以确保在使用super()函数时,可以正确地进行属性查找和方法解析。

0
0 Comments

元类是Python中非常强大的概念,它允许我们在定义类时自定义类的行为和属性。然而,在使用元类时,某些概念可能会令人困惑,特别是与类的继承层次结构和super()函数的关系。

首先,需要明确元类与类的继承层次结构是不同的概念。元类是类的类型,它具有创建类对象本身的模板和方法。元类有构建类的继承顺序(MRO)的机制,并调用类的__new__和__init__方法。当调用一个类对象时,实际上是调用了元类的__call__方法来创建一个新的实例。

其次,super()函数并不是实际的超类,它是一个代理对象,将任何属性检索或方法调用转发到适当的超类。super()函数的内部机制是将调用super()的实例作为自己的__self__属性。当super对象被用作代理来访问实例的"超类"的属性或方法时,它会使用__self__属性指向的实例。

当在元类中使用super()时,被代理的类是元类的超类,而不是Car的超类。这就解释了为什么super(Meta_1, cls).__self__是Car类,并且为什么在元类的__call__方法中调用Car类的__call__方法不会导致循环调用。

在super函数的第一个参数中传递Meta_1是因为通常情况下,第一个参数是定义方法所在的类。它作为MRO搜索的起始点;super(A, obj)返回一个代理对象,该对象在obj的MRO中紧跟在A之后的类。在元类中使用super()时,它并不按照通常的方式使用第一个和第二个参数来代理obj的MRO中A之后的类,而是代理元类的超类。

总之,元类和类的继承层次结构是不同的概念。元类负责创建类对象本身,并通过其__call__方法来创建实例。super()函数是一个代理对象,用于访问实例的"超类"的属性和方法。在元类中使用super()时,被代理的类是元类的超类,而不是Car的超类。

请注意,尽管元类和super()函数非常强大,但在大多数情况下,我们并不需要在代码中使用它们。只有在特定情况下,才需要在子类中使用super()函数。

0