如何从 Python 中的 `super()` 获取实例方法的下一个在线父 class
How do I get the instance method's next-in-line parent class from `super()` in Python
我想知道从 super() 函数获得的实例类型。我尝试了 print(super())
和 __print(type(super()))__
class Base:
def __init__(self):
pass
class Derive(Base):
def __init__(self):
print(super())
print(type(super()))
super().__init__()
d = Derive()
结果是
<super: <class 'Derive'>, <Derive object>>
<class 'super'>
有了这些结果,我想知道 super().__init__()
如何调用正确的构造函数。
你不能直接用 super()
做你想做的事。转到 class MRO(参见 class.__mro__
):
class Derive(Base):
def __init__(self):
mro = type(self).__mro__
parent = mro[mro.index(__class__) + 1]
print(parent)
这里的__class__
是魔法闭包变量*,它引用了定义当前函数的class;即使您使用 class 子class 或将其他 class 与 Derive
混合,即使您生成菱形继承模式,上述内容仍然有效。
演示:
>>> class Base: pass
...
>>> class Derive(Base):
... def __init__(self):
... mro = type(self).__mro__
... parent = mro[mro.index(__class__) + 1]
... print(parent)
...
>>> Derive()
<class '__main__.Base'>
<__main__.Derive object at 0x10f7476a0>
>>> class Mixin(Base): pass
...
>>> class Multiple(Derive, Mixin): pass
...
>>> Multiple()
<class '__main__.Mixin'>
<__main__.Multiple object at 0x10f747ba8>
注意 Multiple
class 是如何从 Derive
和 Mixin
继承的,因此发现 MRO 中的下一个 class 是 Mixin
, not Base
, 因为 Mixin
also 派生自 Base
.
这复制了super()
所做的;在实例的 MRO 中找到下一个 class,相对于当前 class.
* 背景见Why is Python 3.x's super() magic?
根据您的评论,您想知道 super
如何知道接下来要调用哪个方法。 Super 检查实例的 mro,知道它所在的当前 class 方法,然后调用下一个方法。下面的演示将在 Python 2 和 3 中运行,在 Python 2 中,由于元 class,它会打印每个 class 的名称,所以我将使用该输出:
首先导入和设置以使打印更好:
import inspect
class Meta(type):
def __repr__(cls):
return cls.__name__
接下来,我们根据superobject本身定义一个函数来告诉我们发生了什么
def next_in_line(supobj):
print('The instance class: {}'.format(supobj.__self_class__))
print('in this class\'s method: {}'.format(supobj.__thisclass__))
mro = inspect.getmro(supobj.__self_class__)
nextindex = mro.index(supobj.__thisclass__) + 1
print('super will go to {} next'.format(mro[nextindex]))
最后,我们根据维基百科条目 C3 linearization 中的示例声明一个 class 层次结构,对于足够复杂的示例,请注意元 class repr
在 Python3 中不起作用,但属性分配不会破坏它。另请注意,我们使用 super(Name, self)
的完整超级调用,它等效于 Python 3 中的 super()
,并且仍然有效:
class O(object):
__metaclass__ = Meta
def __init__(self):
next_in_line(super(O, self))
super(O, self).__init__()
class A(O):
def __init__(self):
next_in_line(super(A, self))
super(A, self).__init__()
class B(O):
def __init__(self):
next_in_line(super(B, self))
super(B, self).__init__()
class C(O):
def __init__(self):
next_in_line(super(C, self))
super(C, self).__init__()
class D(O):
def __init__(self):
next_in_line(super(D, self))
super(D, self).__init__()
class E(O):
def __init__(self):
next_in_line(super(E, self))
super(E, self).__init__()
class K1(A, B, C):
def __init__(self):
next_in_line(super(K1, self))
super(K1, self).__init__()
class K2(D, B, E):
def __init__(self):
next_in_line(super(K2, self))
super(K2, self).__init__()
class K3(D, A):
def __init__(self):
next_in_line(super(K3, self))
super(K3, self).__init__()
class Z(K1, K2, K3):
def __init__(self):
next_in_line(super(Z, self))
super(Z, self).__init__()
现在我们打印Z的mro,我们得到了这个算法定义的方法解析顺序应用于继承树:
>>> print(inspect.getmro(Z))
(Z, K1, K2, K3, D, A, B, C, E, O, <type 'object'>)
而当我们调用 Z() 时,因为我们的函数使用了 mro,所以我们将按顺序访问每个方法:
>>> Z()
The instance class: Z
in this class's method: Z
super will go to K1 next
The instance class: Z
in this class's method: K1
super will go to K2 next
The instance class: Z
in this class's method: K2
super will go to K3 next
The instance class: Z
in this class's method: K3
super will go to D next
The instance class: Z
in this class's method: D
super will go to A next
The instance class: Z
in this class's method: A
super will go to B next
The instance class: Z
in this class's method: B
super will go to C next
The instance class: Z
in this class's method: C
super will go to E next
The instance class: Z
in this class's method: E
super will go to O next
The instance class: Z
in this class's method: O
super will go to <type 'object'> next
我们停在 object.__init__
。从上面我们可以看出super
总是知道它所在的实例class,它当前所在的class的方法,并且可以从实例中推导出class 的 MRO 下一步要去哪里。
I'd like to know the name of the base class?
如果你只想要直接基(或多个,在多重继承的情况下),你可以使用__bases__
属性,其中returns一个元组
>>> Derive.__bases__
(<class __main__.Base at 0xffeb517c>,)
>>> Derive.__bases__[0].__name__
'Base'
我推荐用于获取方法解析顺序的检查模块(super
根据原始调用者的 class 遵循):
>>> import inspect
>>> inspect.getmro(Derive)
(<class __main__.Derive at 0xffeb51dc>, <class __main__.Base at 0xffeb517c>)
从超级获取
super().__self_class__
给出实例 class,super().__thisclass__
给出当前 class。我们可以使用实例的 MRO 并查找接下来出现的 class。我想你不会在最后 parent 中这样做,所以我没有发现索引错误:
class Base:
def __init__(self):
print(super().__self_class__)
print(super().__thisclass__)
class Derive(Base):
def __init__(self):
print(super().__self_class__)
print(super().__thisclass__)
mro = inspect.getmro(super().__self_class__)
nextindex = mro.index(super().__thisclass__) + 1
print('super will go to {} next'.format(mro[nextindex]))
super().__init__()
>>> d = Derive()
<class '__main__.Derive'>
<class '__main__.Derive'>
super will go to <class '__main__.Base'> next
<class '__main__.Derive'>
<class '__main__.Base'>
我想知道从 super() 函数获得的实例类型。我尝试了 print(super())
和 __print(type(super()))__
class Base:
def __init__(self):
pass
class Derive(Base):
def __init__(self):
print(super())
print(type(super()))
super().__init__()
d = Derive()
结果是
<super: <class 'Derive'>, <Derive object>>
<class 'super'>
有了这些结果,我想知道 super().__init__()
如何调用正确的构造函数。
你不能直接用 super()
做你想做的事。转到 class MRO(参见 class.__mro__
):
class Derive(Base):
def __init__(self):
mro = type(self).__mro__
parent = mro[mro.index(__class__) + 1]
print(parent)
这里的__class__
是魔法闭包变量*,它引用了定义当前函数的class;即使您使用 class 子class 或将其他 class 与 Derive
混合,即使您生成菱形继承模式,上述内容仍然有效。
演示:
>>> class Base: pass
...
>>> class Derive(Base):
... def __init__(self):
... mro = type(self).__mro__
... parent = mro[mro.index(__class__) + 1]
... print(parent)
...
>>> Derive()
<class '__main__.Base'>
<__main__.Derive object at 0x10f7476a0>
>>> class Mixin(Base): pass
...
>>> class Multiple(Derive, Mixin): pass
...
>>> Multiple()
<class '__main__.Mixin'>
<__main__.Multiple object at 0x10f747ba8>
注意 Multiple
class 是如何从 Derive
和 Mixin
继承的,因此发现 MRO 中的下一个 class 是 Mixin
, not Base
, 因为 Mixin
also 派生自 Base
.
这复制了super()
所做的;在实例的 MRO 中找到下一个 class,相对于当前 class.
* 背景见Why is Python 3.x's super() magic?
根据您的评论,您想知道 super
如何知道接下来要调用哪个方法。 Super 检查实例的 mro,知道它所在的当前 class 方法,然后调用下一个方法。下面的演示将在 Python 2 和 3 中运行,在 Python 2 中,由于元 class,它会打印每个 class 的名称,所以我将使用该输出:
首先导入和设置以使打印更好:
import inspect
class Meta(type):
def __repr__(cls):
return cls.__name__
接下来,我们根据superobject本身定义一个函数来告诉我们发生了什么
def next_in_line(supobj):
print('The instance class: {}'.format(supobj.__self_class__))
print('in this class\'s method: {}'.format(supobj.__thisclass__))
mro = inspect.getmro(supobj.__self_class__)
nextindex = mro.index(supobj.__thisclass__) + 1
print('super will go to {} next'.format(mro[nextindex]))
最后,我们根据维基百科条目 C3 linearization 中的示例声明一个 class 层次结构,对于足够复杂的示例,请注意元 class repr
在 Python3 中不起作用,但属性分配不会破坏它。另请注意,我们使用 super(Name, self)
的完整超级调用,它等效于 Python 3 中的 super()
,并且仍然有效:
class O(object):
__metaclass__ = Meta
def __init__(self):
next_in_line(super(O, self))
super(O, self).__init__()
class A(O):
def __init__(self):
next_in_line(super(A, self))
super(A, self).__init__()
class B(O):
def __init__(self):
next_in_line(super(B, self))
super(B, self).__init__()
class C(O):
def __init__(self):
next_in_line(super(C, self))
super(C, self).__init__()
class D(O):
def __init__(self):
next_in_line(super(D, self))
super(D, self).__init__()
class E(O):
def __init__(self):
next_in_line(super(E, self))
super(E, self).__init__()
class K1(A, B, C):
def __init__(self):
next_in_line(super(K1, self))
super(K1, self).__init__()
class K2(D, B, E):
def __init__(self):
next_in_line(super(K2, self))
super(K2, self).__init__()
class K3(D, A):
def __init__(self):
next_in_line(super(K3, self))
super(K3, self).__init__()
class Z(K1, K2, K3):
def __init__(self):
next_in_line(super(Z, self))
super(Z, self).__init__()
现在我们打印Z的mro,我们得到了这个算法定义的方法解析顺序应用于继承树:
>>> print(inspect.getmro(Z))
(Z, K1, K2, K3, D, A, B, C, E, O, <type 'object'>)
而当我们调用 Z() 时,因为我们的函数使用了 mro,所以我们将按顺序访问每个方法:
>>> Z()
The instance class: Z
in this class's method: Z
super will go to K1 next
The instance class: Z
in this class's method: K1
super will go to K2 next
The instance class: Z
in this class's method: K2
super will go to K3 next
The instance class: Z
in this class's method: K3
super will go to D next
The instance class: Z
in this class's method: D
super will go to A next
The instance class: Z
in this class's method: A
super will go to B next
The instance class: Z
in this class's method: B
super will go to C next
The instance class: Z
in this class's method: C
super will go to E next
The instance class: Z
in this class's method: E
super will go to O next
The instance class: Z
in this class's method: O
super will go to <type 'object'> next
我们停在 object.__init__
。从上面我们可以看出super
总是知道它所在的实例class,它当前所在的class的方法,并且可以从实例中推导出class 的 MRO 下一步要去哪里。
I'd like to know the name of the base class?
如果你只想要直接基(或多个,在多重继承的情况下),你可以使用__bases__
属性,其中returns一个元组
>>> Derive.__bases__
(<class __main__.Base at 0xffeb517c>,)
>>> Derive.__bases__[0].__name__
'Base'
我推荐用于获取方法解析顺序的检查模块(super
根据原始调用者的 class 遵循):
>>> import inspect
>>> inspect.getmro(Derive)
(<class __main__.Derive at 0xffeb51dc>, <class __main__.Base at 0xffeb517c>)
从超级获取
super().__self_class__
给出实例 class,super().__thisclass__
给出当前 class。我们可以使用实例的 MRO 并查找接下来出现的 class。我想你不会在最后 parent 中这样做,所以我没有发现索引错误:
class Base:
def __init__(self):
print(super().__self_class__)
print(super().__thisclass__)
class Derive(Base):
def __init__(self):
print(super().__self_class__)
print(super().__thisclass__)
mro = inspect.getmro(super().__self_class__)
nextindex = mro.index(super().__thisclass__) + 1
print('super will go to {} next'.format(mro[nextindex]))
super().__init__()
>>> d = Derive()
<class '__main__.Derive'>
<class '__main__.Derive'>
super will go to <class '__main__.Base'> next
<class '__main__.Derive'>
<class '__main__.Base'>