サーチ…


前書き

メタクラスでは、新しいクラスがデフォルトで使用する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のどちらを使用するかによって異なります。

Python 2.x 2.7

特別なクラスレベルの属性__metaclass__を使用して、メタクラスを指定することができます。

class MyDummy(object):
    __metaclass__ = mytype
type(MyDummy)  # <class '__main__.mytype'>
Python 3.x 3.0

特別なmetaclassキーワード引数は、メタクラスを指定します。

class MyDummy(metaclass=mytype):
    pass
type(MyDummy)  # <class '__main__.mytype'>

クラス宣言のキーワード引数( metaclassを除く)は、すべてmetaclassに渡されます。したがって、 class MyDummy(metaclass=mytype, x=2)は、キーワード引数としてx=2mytypeコンストラクタに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
Python 2.x 2.7
class MySingleton(object):
    __metaclass__ = SingletonType
Python 3.x 3.0
class MySingleton(metaclass=SingletonType):
    pass
MySingleton() is MySingleton()  # True, only one instantiation occurs

メタクラスの使用

メタクラス構文

Python 2.x 2.7
class MyClass(object):
    __metaclass__ = SomeMetaclass
Python 3.x 3.0
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

ニース、 barFooインスタンスです。しかしFoo自身のクラスは何ですか?

>>> type(Foo)
type

OK、 Foo自体がtypeインスタンスです。 type自体はどうですか?

>>> type(type)
type

だからメタクラスは何ですか?今のところ、それはクラスのクラスのちょうど派手な名前であるふりをすることができます。テイクアウト:

  • すべてがPythonのオブジェクトであるため、すべてにクラスがあります
  • クラスのクラスはメタクラスと呼ばれます
  • デフォルトのメタクラスはtypeであり、それはこれまでのところ最も一般的なメタクラスです

しかし、なぜあなたはメタクラスについて知っているべきですか?あなたがメタプログラミングのような高度な作業をしている場合や、クラスの初期化方法を制御したい場合、Python自体はかなり「ハック可能」で、メタクラスの概念は重要です。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow