OK、ここでかなりの数の概念をミックスに投入しました! 皆様から寄せられた具体的なご質問を抜粋してご紹介します。
一般に、super、MRO、および metclasses を理解することは、Python の最後のいくつかのバージョンでこの扱いにくい領域に多くの変更が加えられたため、はるかに複雑になっています。
Python 自身のドキュメントは非常に優れたリファレンスであり、完全に最新のものです。入門としては適切で、よりチュートリアルベースのアプローチをとるIBM developerWorks の記事がありますが、それは 5 年前のものであり、メタクラスに対する古いスタイルのアプローチについて多くの時間を費やしていることに注意してください。
super
オブジェクトのスーパークラスにアクセスする方法です。super
主に Python の多重継承のため、(たとえば) Java のキーワードよりも複雑です。Super Considered Harmfulが説明しているように、使用すると、メソッド解決順序(MRO)super()
によって定義される順序であるスーパークラスのチェーンを暗黙的に使用することになります。
mro()
(インスタンスではなく) クラスを呼び出すことにより、クラスの MRO を簡単に確認できます。メタクラスはオブジェクトのスーパークラス階層には含まれないことに注意してください。
ここでのThomasのメタクラスの説明は優れています。
メタクラスはクラスのクラスです。クラスがクラスのインスタンスの動作を定義するように、メタクラスはクラスの動作を定義します。クラスはメタクラスのインスタンスです。
あなたが与える例では、何が起こっているのですか:
への呼び出し__new__
は、MRO の次のものにバブルアップされています。この場合、;super(MyType, cls)
に解決されます。type
を呼び出すとtype.__new__
、Python は通常のインスタンス作成手順を完了できます。
この例では、メタクラスを使用してシングルトンを適用しています。彼はメタクラスでオーバーライド__call__
しているため、クラス インスタンスが作成されるたびにそれをインターセプトし、インスタンスが既に存在する場合はインスタンスの作成をバイパスできます ( に格納されていますcls.instance
)。クラスを作成するときにのみ呼び出されるため、メタクラスでのオーバーライド__new__
は十分ではないことに注意してください。ただし、クラスのオーバーライド
は機能します。__new__
これは、クラスを動的に作成する方法を示しています。ここでは、提供されたクラスの名前を作成されたクラス名に追加し、それをクラス階層にも追加しています。
どのようなコード例を探しているのか正確にはわかりませんが、メタクラス、継承、およびメソッド解決を示す簡単な例を次に示します。
print('>>> # Defining classes:')
class MyMeta(type):
def __new__(cls, name, bases, dct):
print("meta: creating %s %s" % (name, bases))
return type.__new__(cls, name, bases, dct)
def meta_meth(cls):
print("MyMeta.meta_meth")
__repr__ = lambda c: c.__name__
class A(metaclass=MyMeta):
def __init__(self):
super(A, self).__init__()
print("A init")
def meth(self):
print("A.meth")
class B(metaclass=MyMeta):
def __init__(self):
super(B, self).__init__()
print("B init")
def meth(self):
print("B.meth")
class C(A, B, metaclass=MyMeta):
def __init__(self):
super(C, self).__init__()
print("C init")
print('>>> c_obj = C()')
c_obj = C()
print('>>> c_obj.meth()')
c_obj.meth()
print('>>> C.meta_meth()')
C.meta_meth()
print('>>> c_obj.meta_meth()')
c_obj.meta_meth()
出力例 (Python >= 3.6 を使用):
>>> # Defining classes:
meta: creating A ()
meta: creating B ()
meta: creating C (A, B)
>>> c_obj = C()
B init
A init
C init
>>> c_obj.meth()
A.meth
>>> C.meta_meth()
MyMeta.meta_meth
>>> c_obj.meta_meth()
Traceback (most recent call last):
File "metatest.py", line 41, in <module>
c_obj.meta_meth()
AttributeError: 'C' object has no attribute 'meta_meth'