调用super()时,元类如何与MRO列表一起使用? [英] how does metaclass work with the MRO list when super() is called?
问题描述
以下代码示例让我很困惑:
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__()
结果显示第4行的cls
是Car
类,并且其MRO列表是:
[<class '__main__.Car'>, <class 'object'>]
但是,第6行显示super(Meta_1, cls).__self__
也是Car
类.
我真的很困惑:
- 在第7行中,看来
super(Meta_1, cls).__call__(*a, **kw)
最终导致了type.__call__
. 但是,据我所知,super(arg1, arg2)
将调查第二个输入参数的MRO,以找到第一个输入参数,并将下一个类返回给它.但是在我的代码的第6和第7行中,第二个参数(Car
)的MRO不包含第一个输入参数(Meta_1
),您无法在Car
的MRO中找到Meta_1
.那么为什么super(Meta_1, cos)
带我们去调用type.__call__
呢?
2.如果 super(Meta_1, cls).__self__
是Car
类,那么第7行表示正在调用的是Car
的__call__
吗?但是调用Car
类使我们首先进入了第1行,对吗?那不是循环吗?
重要的是要注意将什么值用作super
的每个参数. super
的主要目的是根据某些方法解析顺序(MRO)执行属性查找.第二个参数确定要使用哪个MRO;首先确定开始的位置.
MRO始终由 class 定义;在对实例执行方法解析时,我们使用该实例为类型的类的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_1.__call__
的某个对象.这意味着我们将使用type(cls)
提供的MRO,并且将使用在之后 Meta_1
之后找到的第一个类,该类提供了所需的方法. (在第一次调用中,__self__
是代理对象本身的属性,而不是其代理super
返回的类的属性或方法.)
运行代码时,您会看到cls
已绑定到Car
类型的对象.这是因为Car()
是由type(Car).__call__()
实现的;由于Car
使用Meta_1
作为其元类,所以type(Car)
是Meta_1
.
cls.mro()
是无关紧要的,因为那是cls
的 instances 所使用的MRO.
Meta_1
本身的MRO可以通过
>>> Meta_1.mro(Meta_1)
[<class '__main__.Meta_1'>, <class 'type'>, <class 'object'>]
(mro
是type
类的实例方法,因此需要type
的表面冗余实例作为参数.请记住,cls.mro()
等效于type(cls).mro(cls)
.)>
所以第7行是对type.__call__
的调用,以便创建cls
可以返回的cls
实例.
I'm really confused by the following code sample:
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()
The print message for this code is:
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__()
The result shows that cls
of line 4 is the Car
class and its MRO list is:
[<class '__main__.Car'>, <class 'object'>]
However, line 6 shows that super(Meta_1, cls).__self__
is also the Car
class.
I am really confused that:
- In line 7, It seems that
super(Meta_1, cls).__call__(*a, **kw)
eventually lead totype.__call__
. But, to my knowledge,super(arg1, arg2)
will look into the MRO of the second input argument to find the first input argument, and return the next class to it. But in line 6 and 7 of my code, the MRO for 2nd argument(Car
), does not contain the 1st input argument(Meta_1
), you cannot findMeta_1
in the MRO forCar
. so why wouldsuper(Meta_1, cos)
take us to invoketype.__call__
??
2. if super(Meta_1, cls).__self__
is the Car
class, then line 7 means it's Car
's __call__
that's being called? But calling the Car
class took us to line 1 in the first place, right? wouldn't that be a loop?
It's important to pay attention to what values are being used as each argument to super
. The primary purpose of super
is to perform attribute lookup according to some method-resolution order (MRO). The second argument determines which MRO to use; the first determines where to start looking.
An MRO is always defined by a class; when performing method resolution on an instance, we use the MRO of the class of which that instance is a type.
In the class
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
we see two uses of super
. Both take the same arguments. cls
is some object passed as the first argument to Meta_1.__call__
. That means we'll use the MRO provided by type(cls)
, and we'll use the first class found after Meta_1
that provides the desired method. (In the first call, __self__
is an attribute of the proxy object itself, rather than an attribute or method of the class whose proxy super
returns.)
When you run your code, you see that cls
is bound to your Car
type object. That's because Car()
is implemented by type(Car).__call__()
; since Car
uses Meta_1
as its metaclass, type(Car)
is Meta_1
.
cls.mro()
is irrelevant, because that's the MRO used by instances of cls
.
The MRO of Meta_1
itself can be seen with
>>> Meta_1.mro(Meta_1)
[<class '__main__.Meta_1'>, <class 'type'>, <class 'object'>]
(mro
is an instance method of the type
class, and so requires the seemingly redundant instance of type
as an argument. Keep in mind that cls.mro()
is equivalent to type(cls).mro(cls)
.)
So line 7 is a call to type.__call__
, in order to create an instance of cls
that Meta_1.__call__
can return.
这篇关于调用super()时,元类如何与MRO列表一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!