あなたのコメントから、super
次に呼び出すメソッドをどのように知っているか知りたいです。Super はインスタンスの mro を検査し、それが含まれている現在のクラス メソッドを認識し、次のメソッドを呼び出します。次のデモは Python 2 および 3 で動作し、Python 2 ではメタクラスのおかげで各クラスの名前が出力されるため、その出力を使用します。
まず、印刷をより良くするためのインポートとセットアップ:
import inspect
class Meta(type):
def __repr__(cls):
return cls.__name__
次に、スーパー オブジェクト自体に基づいて何が起こっているかを示す関数を定義します。
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 線形化に関するウィキペディアのエントリの例に基づいてクラス階層を宣言します。十分に複雑な例として、repr
Python3 ではメタクラスが機能しないことに注意してください。ただし、属性の割り当てによって壊れることはありません。また、Python 3super(Name, self)
と同等の完全な super 呼び出しを使用しており、引き続き機能することにも注意してください。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
はインスタンスのクラス、現在のクラスのメソッドを常に認識しており、インスタンス クラスの MRO から次に進むべき場所を推測できることがわかります。
基本クラスの名前を知りたいのですが?
直接ベース (多重継承の場合は複数) のみが必要な場合は__bases__
、タプルを返す属性を使用できます。
>>> Derive.__bases__
(<class __main__.Base at 0xffeb517c>,)
>>> Derive.__bases__[0].__name__
'Base'
super
Method Resolution Order (元の呼び出し元のクラスに基づく)を取得するには、inspect モジュールをお勧めします。
>>> import inspect
>>> inspect.getmro(Derive)
(<class __main__.Derive at 0xffeb51dc>, <class __main__.Base at 0xffeb517c>)
スーパーから入手
super().__self_class__
インスタンスクラスをsuper().__thisclass__
提供し、現在のクラスを提供します。インスタンスの MRO を使用して、次に来るクラスを検索できます。最終的な親でこれを行うことはないと思うので、インデックスエラーをキャッチしていません:
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'>