Python Language
メタクラス
サーチ…
前書き
メタクラスでは、新しいクラスがデフォルトで使用するtype
メタクラスを置き換えることで、Pythonクラスの動作(定義、インスタンス化、アクセスなどの点で)を深く変更することができます。
備考
アーキテクチャーを設計するときは、メタクラスで達成できる多くのことを、よりシンプルなセマンティクスを使用して達成できることも考慮してください。
- 伝統的な継承はしばしば十分です。
- クラスデコレータは、機能をアドホックアプローチでクラスに組み込むことができます。
- Python 3.6には
__init_subclass__()
が導入されている__init_subclass__()
、クラスはそのサブクラスの作成に参加できます。
基本メタクラス
type
が3つの引数で呼び出されると、それは(メタ)クラスとして動作し、新しいインスタンスを作成します。新しいクラス/型が生成されます。
Dummy = type('OtherDummy', (), dict(x=1))
Dummy.__class__ # <type 'type'>
Dummy().__class__.__class__ # <type 'type'>
type
をサブクラス化してカスタムメタクラスを作成することは可能です。
class mytype(type):
def __init__(cls, name, bases, dict):
# call the base initializer
type.__init__(cls, name, bases, dict)
# perform custom initialization...
cls.__custom_attribute__ = 2
さて、 type
と同じ方法でクラスを作成するために使用できる、新しいカスタムのmytype
メタクラスがあります。
MyDummy = mytype('MyDummy', (), dict(x=2))
MyDummy.__class__ # <class '__main__.mytype'>
MyDummy().__class__.__class__ # <class '__main__.mytype'>
MyDummy.__custom_attribute__ # 2
class
キーワードを使用して新しいクラスを作成すると、メタクラスはデフォルトでベースクーラスに基づいて選択されます。
>>> class Foo(object):
... pass
>>> type(Foo)
type
上記の例では唯一の基底クラスは、 object
我々のメタクラスがタイプであろうように、 object
である、 type
。デフォルトを上書きすることは可能ですが、Python 2とPython 3のどちらを使用するかによって異なります。
特別なクラスレベルの属性__metaclass__
を使用して、メタクラスを指定することができます。
class MyDummy(object):
__metaclass__ = mytype
type(MyDummy) # <class '__main__.mytype'>
特別なmetaclass
キーワード引数は、メタクラスを指定します。
class MyDummy(metaclass=mytype):
pass
type(MyDummy) # <class '__main__.mytype'>
クラス宣言のキーワード引数( metaclass
を除く)は、すべてmetaclass
に渡されます。したがって、 class MyDummy(metaclass=mytype, x=2)
は、キーワード引数としてx=2
をmytype
コンストラクタにmytype
ます。
詳細は、Pythonメタクラスの詳細な説明を読んでください。
メタクラスを使用したシングルトン
シングルトンは、クラスのインスタンス化を1つのインスタンス/オブジェクトに制限するパターンです。 pythonのシングルトンデザインパターンの詳細については、 こちらを参照してください 。
class SingletonType(type):
def __call__(cls, *args, **kwargs):
try:
return cls.__instance
except AttributeError:
cls.__instance = super(SingletonType, cls).__call__(*args, **kwargs)
return cls.__instance
class MySingleton(object):
__metaclass__ = SingletonType
class MySingleton(metaclass=SingletonType):
pass
MySingleton() is MySingleton() # True, only one instantiation occurs
メタクラスの使用
メタクラス構文
class MyClass(object):
__metaclass__ = SomeMetaclass
class MyClass(metaclass=SomeMetaclass):
pass
Python 2および3とsix
との互換性
import six
class MyClass(six.with_metaclass(SomeMetaclass)):
pass
メタクラスによるカスタム機能
メタクラスの機能は 、クラスがビルドされるたびに文字列が標準出力に出力されるか、例外がスローされるように変更することができます。このメタクラスはビルドされるクラスの名前を出力します。
class VerboseMetaclass(type):
def __new__(cls, class_name, class_parents, class_dict):
print("Creating class ", class_name)
new_class = super().__new__(cls, class_name, class_parents, class_dict)
return new_class
あなたは次のようにメタクラスを使うことができます:
class Spam(metaclass=VerboseMetaclass):
def eggs(self):
print("[insert example string here]")
s = Spam()
s.eggs()
標準出力は次のようになります。
Creating class Spam
[insert example string here]
メタクラスの紹介
メタクラスとは何ですか?
Pythonでは、すべてがオブジェクトです。整数、文字列、リスト、さらには関数やクラス自体がオブジェクトです。すべてのオブジェクトはクラスのインスタンスです。
オブジェクトxのクラスを調べるには、 type(x)
呼び出すことができます:
>>> type(5)
<type 'int'>
>>> type(str)
<type 'type'>
>>> type([1, 2, 3])
<type 'list'>
>>> class C(object):
... pass
...
>>> type(C)
<type 'type'>
Pythonのほとんどのクラスはtype
インスタンスです。 type
自体もクラスです。インスタンスがクラスでもあるそのようなクラスは、メタクラスと呼ばれます。
最も単純なメタクラス
:OK、そうPythonで1つのメタクラスすでにあるtype
。別のものを作ることはできますか?
class SimplestMetaclass(type):
pass
class MyClass(object):
__metaclass__ = SimplestMetaclass
これは機能を追加するものではありませんが、新しいメタクラスです.MyClassがSimplestMetaclassのインスタンスになっています。
>>> type(MyClass)
<class '__main__.SimplestMetaclass'>
何かをするメタクラス
クラスを作成する元の__new__
を呼び出す前に、何かを行うメタクラスは通常、 type
の__new__
オーバーライドして、作成するクラスのいくつかのプロパティを変更します:
class AnotherMetaclass(type):
def __new__(cls, name, parents, dct):
# cls is this class
# name is the name of the class to be created
# parents is the list of the class's parent classes
# dct is the list of class's attributes (methods, static variables)
# here all of the attributes can be modified before creating the class, e.g.
dct['x'] = 8 # now the class will have a static variable x = 8
# return value is the new class. super will take care of that
return super(AnotherMetaclass, cls).__new__(cls, name, parents, dct)
デフォルトのメタクラス
Pythonのすべてがオブジェクトであると聞いたことがあります。それは事実であり、すべてのオブジェクトにはクラスがあります:
>>> type(1)
int
リテラル1はint
インスタンスです。クラスを宣言できます:
>>> class Foo(object):
... pass
...
これでインスタンス化できます:
>>> bar = Foo()
bar
のクラスは何ですか?
>>> type(bar)
Foo
ニース、 bar
はFoo
インスタンスです。しかしFoo
自身のクラスは何ですか?
>>> type(Foo)
type
OK、 Foo
自体がtype
インスタンスです。 type
自体はどうですか?
>>> type(type)
type
だからメタクラスは何ですか?今のところ、それはクラスのクラスのちょうど派手な名前であるふりをすることができます。テイクアウト:
- すべてがPythonのオブジェクトであるため、すべてにクラスがあります
- クラスのクラスはメタクラスと呼ばれます
- デフォルトのメタクラスは
type
であり、それはこれまでのところ最も一般的なメタクラスです
しかし、なぜあなたはメタクラスについて知っているべきですか?あなたがメタプログラミングのような高度な作業をしている場合や、クラスの初期化方法を制御したい場合、Python自体はかなり「ハック可能」で、メタクラスの概念は重要です。