Pythonのメタクラスは何ですか?


Answers

オブジェクトとしてのクラス

メタクラスを理解する前に、Pythonでクラスをマスターする必要があります。 そして、Pythonには、Smalltalk言語から借りてきたクラスについての非常に特殊な考えがあります。

ほとんどの言語では、クラスはオブジェクトを生成する方法を記述する単なるコードの一部です。 それはPythonでもまあまあです。

>>> class ObjectCreator(object):
...       pass
...

>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>

しかし、クラスはPythonのそれ以上のものです。 クラスもオブジェクトです。

はい、オブジェクト。

キーワードclassを使用するとすぐに、Pythonはそれを実行してOBJECTを作成します。 命令

>>> class ObjectCreator(object):
...       pass
...

メモリに "ObjectCreator"という名前のオブジェクトを作成します。

このオブジェクト(クラス)自体がオブジェクト(インスタンス)を作成することができ、それがクラスです。

しかしそれでも、それは目的であり、したがって:

  • それを変数に割り当てることができます
  • あなたはそれをコピーすることができます
  • あなたはそれに属性を追加することができます
  • 関数のパラメータとして渡すことができます

例えば:

>>> print(ObjectCreator) # you can print a class because it's an object
<class '__main__.ObjectCreator'>
>>> def echo(o):
...       print(o)
...
>>> echo(ObjectCreator) # you can pass a class as a parameter
<class '__main__.ObjectCreator'>
>>> print(hasattr(ObjectCreator, 'new_attribute'))
False
>>> ObjectCreator.new_attribute = 'foo' # you can add attributes to a class
>>> print(hasattr(ObjectCreator, 'new_attribute'))
True
>>> print(ObjectCreator.new_attribute)
foo
>>> ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable
>>> print(ObjectCreatorMirror.new_attribute)
foo
>>> print(ObjectCreatorMirror())
<__main__.ObjectCreator object at 0x8997b4c>

動的にクラスを作成する

クラスはオブジェクトなので、他のオブジェクトと同様に、その場で作成することができます。

まず、クラスを使用して関数内にクラスを作成できます。

>>> def choose_class(name):
...     if name == 'foo':
...         class Foo(object):
...             pass
...         return Foo # return the class, not an instance
...     else:
...         class Bar(object):
...             pass
...         return Bar
...
>>> MyClass = choose_class('foo')
>>> print(MyClass) # the function returns a class, not an instance
<class '__main__.Foo'>
>>> print(MyClass()) # you can create an object from this class
<__main__.Foo object at 0x89c6d4c>

しかし、ダイナミックではありません。クラス全体を自分で書く必要があるからです。

クラスはオブジェクトなので、何かによって生成されなければなりません。

classキーワードを使用すると、Pythonはこのオブジェクトを自動的に作成します。 しかし、Pythonのほとんどのものと同様、手動で行う方法もあります。

関数type覚えていますか? オブジェクトがどのような型であるかを知る良い古い関数です:

>>> print(type(1))
<type 'int'>
>>> print(type("1"))
<type 'str'>
>>> print(type(ObjectCreator))
<type 'type'>
>>> print(type(ObjectCreator()))
<class '__main__.ObjectCreator'>

まあ、 typeはまったく違った能力を持っていますし、その場でクラスを作成することもできます。 typeはクラスの記述をパラメータとして取り、クラスを返すことができます。

(私が知っているのは、渡したパラメータに応じて同じ関数が2つの全く異なる用途を持つことができないということは愚かです。これはPythonの下位互換性のために問題になります)

typeは次のように動作します:

type(name of the class,
     tuple of the parent class (for inheritance, can be empty),
     dictionary containing attributes names and values)

例えば:

>>> class MyShinyClass(object):
...       pass

この方法で手動で作成することができます:

>>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object
>>> print(MyShinyClass)
<class '__main__.MyShinyClass'>
>>> print(MyShinyClass()) # create an instance with the class
<__main__.MyShinyClass object at 0x8997cec>

クラスの名前として "MyShinyClass"を使用し、クラス参照を保持する変数として使用することに気づくでしょう。 彼らは違うかもしれませんが、事を複雑にする理由はありません。

typeは、クラスの属性を定義するための辞書を受け入れます。 そう:

>>> class Foo(object):
...       bar = True

翻訳できる:

>>> Foo = type('Foo', (), {'bar':True})

そして通常のクラスとして使用されます:

>>> print(Foo)
<class '__main__.Foo'>
>>> print(Foo.bar)
True
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x8a9b84c>
>>> print(f.bar)
True

もちろん、あなたはそれを継承することができます:

>>>   class FooChild(Foo):
...         pass

だろう:

>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
<class '__main__.FooChild'>
>>> print(FooChild.bar) # bar is inherited from Foo
True

最終的に、クラスにメソッドを追加したいと思うでしょう。 適切な署名を持つ関数を定義し、それを属性として割り当てます。

>>> def echo_bar(self):
...       print(self.bar)
...
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
>>> hasattr(Foo, 'echo_bar')
False
>>> hasattr(FooChild, 'echo_bar')
True
>>> my_foo = FooChild()
>>> my_foo.echo_bar()
True

また、通常作成されたクラスオブジェクトにメソッドを追加するのと同じように、クラスを動的に作成した後でさらにメソッドを追加できます。

>>> def echo_bar_more(self):
...       print('yet another method')
...
>>> FooChild.echo_bar_more = echo_bar_more
>>> hasattr(FooChild, 'echo_bar_more')
True

私たちはどこに行くのか見ていきます。Pythonでは、クラスはオブジェクトであり、動的にクラスを動的に作成することができます。

これは、キーワードclassを使用するときにPythonが実行する動作で、メタクラスを使用することによって実行されます。

メタクラスとは(最終的に)

メタクラスはクラスを作成する 'もの'です。

オブジェクトを作成するためにクラスを定義するのは正しいでしょうか?

しかし、私たちはPythonクラスがオブジェクトであることを学びました。

さて、これらのオブジェクトを作成するのはメタクラスです。 彼らはクラスのクラスです、あなたはそれらをこのように描くことができます:

MyClass = MetaClass()
my_object = MyClass()

あなたは、あなたが次のようなことをすることができることを見てきました:

MyClass = type('MyClass', (), {})

これは、関数typeが実際にはメタクラスであるためです。 typeは、Pythonがバックグラウンドですべてのクラスを作成するために使用するメタクラスです。

さて、なぜあなたはそれが小文字で書かれているのだろうと思っています。

文字列オブジェクトを作成するクラスstrと整数オブジェクトを作成するクラスintとの一貫性の問題だと思います。 typeはクラスオブジェクトを作成するクラスです。

それは__class__属性をチェックすることで__class__ます。

すべて、そして私はすべてを意味し、Pythonのオブジェクトです。 これには、int、文字列、関数、クラスが含まれます。 それらはすべてオブジェクトです。 そしてそれらのすべてはクラスから作成されています:

>>> age = 35
>>> age.__class__
<type 'int'>
>>> name = 'bob'
>>> name.__class__
<type 'str'>
>>> def foo(): pass
>>> foo.__class__
<type 'function'>
>>> class Bar(object): pass
>>> b = Bar()
>>> b.__class__
<class '__main__.Bar'>

今、 __class__は何__class__

>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>

ですから、メタクラスはクラスオブジェクトを作成するだけのものです。

あなたが望むなら、それを「クラスファクトリー」と呼ぶことができます。

typeは組み込みのメタクラスPythonが使用するものですが、もちろん独自のメタクラスを作成することもできます。

__metaclass__属性

クラスを書くときに__metaclass__属性を追加することができます:

class Foo(object):
    __metaclass__ = something...
    [...]

そうすると、Pythonはメタクラスを使ってクラスFooを作成します。

細心の注意を払っています。

class Foo(object)最初に書きclass Foo(object)が、クラスオブジェクトFooはまだメモリに作成されていません。

Pythonはクラス定義で__metaclass__を探します。 見つかった場合は、それを使用してオブジェクトクラスFooを作成します。 そうでなければ、 typeを使ってクラスを作成します。

それを数回読んでください。

あなたがするとき:

class Foo(Bar):
    pass

Pythonは以下を行います:

Foo __metaclass__属性がありますか?

もしそうなら、 __metaclass__ものを使ってFooという名前でクラスオブジェクト(私はここでクラスオブジェクトと言っています)をメモリに作成します。

Pythonが__metaclass__見つけられない場合は、MODULEレベルで__metaclass__を探し、 __metaclass__を継承しないクラス(基本的に古いスタイルのクラスのみ)で同じことを試みます。

そして、__metaclass__がまったく見つからない場合は、クラスのオブジェクトを作成するためにBar (最初の親)のメタクラス(デフォルトのtypeかもしれません)を使用します。

__metaclass__属性が継承されないように注意してください。親( Bar.__class__ )のメタクラスが継承されます。 Bartype()type.__new__()type.__new__()ではなくBarを作成した__metaclass__属性を使用した場合、サブクラスはその動作を継承しません。

今大きな問題は、 __metaclass__何を入れることができるかということです。

答えは、クラスを作成できるものです。

クラスを作ることができるのは何ですか? type 、またはそれをサブクラス化または使用するもの。

カスタムメタクラス

メタクラスの主な目的は、作成時にクラスを自動的に変更することです。

通常は、現在のコンテキストと一致するクラスを作成するAPIに対してこれを行います。

あなたのモジュール内のすべてのクラスが大文字で書かれた属性を持つべきだと決める愚かな例を想像してみてください。 これを行うにはいくつかの方法がありますが、モジュールレベルで__metaclass__を設定する方法もあります。

このようにして、このモジュールのすべてのクラスはこのメタクラスを使用して作成され、すべての属性を大文字にするようにメタクラスに指示するだけで済みます。

幸いなことに、 __metaclass__は実際には__metaclass__ことができますが、正式なクラスである必要はありません(私の知っているように、クラスの名前はクラスである必要はありません。

だから、関数を使って簡単な例から始めましょう。

# the metaclass will automatically get passed the same argument
# that you usually pass to `type`
def upper_attr(future_class_name, future_class_parents, future_class_attr):
    """
      Return a class object, with the list of its attribute turned
      into uppercase.
    """

    # pick up any attribute that doesn't start with '__' and uppercase it
    uppercase_attr = {}
    for name, val in future_class_attr.items():
        if not name.startswith('__'):
            uppercase_attr[name.upper()] = val
        else:
            uppercase_attr[name] = val

    # let `type` do the class creation
    return type(future_class_name, future_class_parents, uppercase_attr)

__metaclass__ = upper_attr # this will affect all classes in the module

class Foo(): # global __metaclass__ won't work with "object" though
    # but we can define __metaclass__ here instead to affect only this class
    # and this will work with "object" children
    bar = 'bip'

print(hasattr(Foo, 'bar'))
# Out: False
print(hasattr(Foo, 'BAR'))
# Out: True

f = Foo()
print(f.BAR)
# Out: 'bip'

さて、まったく同じようにしましょうが、実際のクラスをメタクラスに使用しましょう:

# remember that `type` is actually a class like `str` and `int`
# so you can inherit from it
class UpperAttrMetaclass(type):
    # __new__ is the method called before __init__
    # it's the method that creates the object and returns it
    # while __init__ just initializes the object passed as parameter
    # you rarely use __new__, except when you want to control how the object
    # is created.
    # here the created object is the class, and we want to customize it
    # so we override __new__
    # you can do some stuff in __init__ too if you wish
    # some advanced use involves overriding __call__ as well, but we won't
    # see this
    def __new__(upperattr_metaclass, future_class_name,
                future_class_parents, future_class_attr):

        uppercase_attr = {}
        for name, val in future_class_attr.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return type(future_class_name, future_class_parents, uppercase_attr)

しかし、これは本当にOOPではありません。 type直接呼びますが、親をオーバーライドしたり__new__呼び出すことはありません。 やってみましょう:

class UpperAttrMetaclass(type):

    def __new__(upperattr_metaclass, future_class_name,
                future_class_parents, future_class_attr):

        uppercase_attr = {}
        for name, val in future_class_attr.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        # reuse the type.__new__ method
        # this is basic OOP, nothing magic in there
        return type.__new__(upperattr_metaclass, future_class_name,
                            future_class_parents, uppercase_attr)

余分な引数upperattr_metaclass気づいたかもしれません。 特別なことは何もありません__new__は、最初に定義されたクラスを常に最初のパラメータとして受け取ります。 インスタンスを最初のパラメータとして受け取る通常のメソッド、またはクラスメソッドの定義クラスのためのselfを持っているように。

もちろん、私がここで使った名前は分かりやすくするために長いですが、 selfように、すべての議論は従来の名前を持っています。 したがって、実際の制作メタクラスは次のようになります。

class UpperAttrMetaclass(type):

    def __new__(cls, clsname, bases, dct):

        uppercase_attr = {}
        for name, val in dct.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return type.__new__(cls, clsname, bases, uppercase_attr)

継承を簡単にするsuperを使用することで、より洗練されたものにすることができます(メタクラスを継承し、メタクラスを継承し、継承します)。

class UpperAttrMetaclass(type):

    def __new__(cls, clsname, bases, dct):

        uppercase_attr = {}
        for name, val in dct.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, uppercase_attr)

それでおしまい。 実際にはメタクラスについては何もありません。

メタクラスを使用するコードの複雑さの背後にある理由は、メタクラスのためではありません。なぜなら、通常、メタクラスを使用してイントロスペクション、継承の操作、__dict__などの変数などに依存するねじれた処理を行うからです。

確かに、メタクラスは黒い魔法を実行するのに特に役に立ち、したがって複雑なものです。 しかし、それ自体はシンプルです。

  • クラス作成を傍受する
  • クラスを変更する
  • 変更されたクラスを返す

なぜ関数の代わりにメタクラスクラスを使うのですか?

__metaclass__は呼び出し可能なものを受け入れることができるので、明らかにもっと複雑なので、なぜクラスを使うのですか?

これにはいくつかの理由があります。

  • その意図ははっきりしています。 あなたがUpperAttrMetaclass(type)を読むと、あなたは何が続くのか知っています
  • あなたはOOPを使うことができます。 メタクラスはメタクラスを継承し、親メソッドをオーバーライドすることができます。 メタクラスはメタクラスを使用することもできます。
  • クラスのサブクラスは、メタクラスクラスを指定した場合はそのメタクラスのインスタンスになりますが、メタクラス関数ではない場合は、そのメタクラスのインスタンスになります。
  • コードをよりよく構造化することができます。 上記の例のように、何かのことでメタクラスを使用することは決してありません。 これは通常、何か複雑なものです。 複数のメソッドを作成して1つのクラスにグループ化することは、コードを読みやすくするために非常に便利です。
  • __new____new____new__にフックでき__call__ 。 これは、あなたが別のものを行うことができます。 通常は__new__ですべてを行うことができますが、 __new__を使うほうが快適です。
  • これらはメタクラスと呼ばれています。 何かを意味する必要があります!

なぜメタクラスを使用しますか?

今大きな問題です。 なぜ、あいまいなエラーが発生しやすい機能を使用しますか?

まあ、あなたはしない:

メタクラスは、ユーザーの99%が心配するべきではない深い魔法です。 あなたがそれらを必要としているかどうか疑問に思うなら、あなたは(実際に必要とする人々は、彼らが必要とすることを確実に知り、理由について説明する必要はありません)。

Python Guru Tim Peters

メタクラスの主な使用例は、APIを作成することです。 これの典型的な例は、Django ORMです。

このように定義することができます:

class Person(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()

しかし、あなたがこれを行う場合:

guy = Person(name='bob', age='35')
print(guy.age)

IntegerFieldオブジェクトは返されません。 intを返し、データベースから直接取得することもできます。

これは可能ですmodels.Model__metaclass__を定義しています。単純な文で定義したPersonをデータベースフィールドの複雑なフックに変換するいくつかの魔法を使用しています。

Djangoは、シンプルなAPIを公開し、メタクラスを使用してこのAPIのコードを再作成することで複雑な外観をシンプルにしています。

最後の言葉

まず、クラスはインスタンスを作成できるオブジェクトであることがわかります。

実際、クラス自体はインスタンスです。 メタクラスの

>>> class Foo(object): pass
>>> id(Foo)
142630324

すべてがPythonのオブジェクトであり、それらはすべてクラスのインスタンスまたはメタクラスのインスタンスのいずれかです。

type除く。

typeは実際には独自のメタクラスです。 これは、純粋なPythonで再現できるものではなく、実装レベルでちょっとした欺瞞をしています。

第二に、メタクラスは複雑です。 非常に簡単なクラス変更には使用したくないかもしれません。 次の2つの方法を使用してクラスを変更できます。

クラスの変更が必要な時間の99%は、これらを使用する方がよいでしょう。

しかし、98%の時間で、クラスの変更はまったく必要ありません。

Question

メタクラスとは何ですか?私たちはそれを何のために使用しますか?




The type() function can return the type of an object or create a new type,

for example, we can create a Hi class with the type() function and do not need to use this way with class Hi(object):

def func(self, name='mike'):
    print('Hi, %s.' % name)

Hi = type('Hi', (object,), dict(hi=func))
h = Hi()
h.hi()
Hi, mike.

type(Hi)
type

type(h)
__main__.Hi

In addition to using type() to create classes dynamically, you can control creation behavior of class and use metaclass.

According to the Python object model, the class is the object, so the class must be an instance of another certain class. By default, a Python class is instance of the type class. That is, type is metaclass of most of the built-in classes and metaclass of user-defined classes.

class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

class CustomList(list, metaclass=ListMetaclass):
    pass

lst = CustomList()
lst.add('custom_list_1')
lst.add('custom_list_2')

lst
['custom_list_1', 'custom_list_2']

Magic will take effect when we passed keyword arguments in metaclass, it indicates the Python interpreter to create the CustomList through ListMetaclass. new (), at this point, we can modify the class definition, for example, and add a new method and then return the revised definition.




Python 3 update

There are (at this point) two key methods in a metaclass:

  • __prepare__ , and
  • __new__

__prepare__ lets you supply a custom mapping (such as an OrderedDict ) to be used as the namespace while the class is being created. You must return an instance of whatever namespace you choose. If you don't implement __prepare__ a normal dict is used.

__new__ is responsible for the actual creation/modification of the final class.

A bare-bones, do-nothing-extra metaclass would like:

class Meta(type):

    def __prepare__(metaclass, cls, bases):
        return dict()

    def __new__(metacls, cls, bases, clsdict):
        return super().__new__(metacls, cls, bases, clsdict)

簡単な例:

Say you want some simple validation code to run on your attributes -- like it must always be an int or a str . Without a metaclass, your class would look something like:

class Person:
    weight = ValidateType('weight', int)
    age = ValidateType('age', int)
    name = ValidateType('name', str)

As you can see, you have to repeat the name of the attribute twice. This makes typos possible along with irritating bugs.

A simple metaclass can address that problem:

class Person(metaclass=Validator):
    weight = ValidateType(int)
    age = ValidateType(int)
    name = ValidateType(str)

This is what the metaclass would look like (not using __prepare__ since it is not needed):

class Validator(type):
    def __new__(metacls, cls, bases, clsdict):
        # search clsdict looking for ValidateType descriptors
        for name, attr in clsdict.items():
            if isinstance(attr, ValidateType):
                attr.name = name
                attr.attr = '_' + name
        # create final class and return it
        return super().__new__(metacls, cls, bases, clsdict)

A sample run of:

p = Person()
p.weight = 9
print(p.weight)
p.weight = '9'

次を生成する:

9
Traceback (most recent call last):
  File "simple_meta.py", line 36, in <module>
    p.weight = '9'
  File "simple_meta.py", line 24, in __set__
    (self.name, self.type, value))
TypeError: weight must be of type(s) <class 'int'> (got '9')

Note : This example is simple enough it could have also been accomplished with a class decorator, but presumably an actual metaclass would be doing much more.

The 'ValidateType' class for reference:

class ValidateType:
    def __init__(self, type):
        self.name = None  # will be set by metaclass
        self.attr = None  # will be set by metaclass
        self.type = type
    def __get__(self, inst, cls):
        if inst is None:
            return self
        else:
            return inst.__dict__[self.attr]
    def __set__(self, inst, value):
        if not isinstance(value, self.type):
            raise TypeError('%s must be of type(s) %s (got %r)' %
                    (self.name, self.type, value))
        else:
            inst.__dict__[self.attr] = value



The tl;dr version

The type(obj) function gets you the type of an object.

The type() of a class is its metaclass .

To use a metaclass:

class Foo(object):
    __metaclass__ = MyMetaClass



Role of a metaclass's __call__() method when creating a class instance

If you've done Python programming for more than a few months you'll eventually stumble upon code that looks like this:

# define a class
class SomeClass(object):
    # ...
    # some definition here ...
    # ...

# create an instance of it
instance = SomeClass()

# then call the object as if it's a function
result = instance('foo', 'bar')

The latter is possible when you implement the __call__() magic method on the class.

class SomeClass(object):
    # ...
    # some definition here ...
    # ...

    def __call__(self, foo, bar):
        return bar + foo

The __call__() method is invoked when an instance of a class is used as a callable. But as we've seen from previous answers a class itself is an instance of a metaclass, so when we use the class as a callable (ie when we create an instance of it) we're actually calling its metaclass's __call__() method. At this point most Python programmers are a bit confused because they've been told that when creating an instance like this instance = SomeClass() you're calling it's __init__() method. Some who've dug a bit deeper know that before __init__() there's __new__() . Well, today another layer of truth is being revealed, before __new__() there's the metaclass's __call__() .

Let's study the method call chain from specifically the perspective of creating an instance of a class.

This is a metaclass that logs exactly the moment before an instance is created and the moment it's about to return it.

class Meta_1(type):
    def __call__(cls):
        print "Meta_1.__call__() before creating an instance of ", cls
        instance = super(Meta_1, cls).__call__()
        print "Meta_1.__call__() about to return instance."
        return instance

This is a class that uses that metaclass

class Class_1(object):

    __metaclass__ = Meta_1

    def __new__(cls):
        print "Class_1.__new__() before creating an instance."
        instance = super(Class_1, cls).__new__(cls)
        print "Class_1.__new__() about to return instance."
        return instance

    def __init__(self):
        print "entering Class_1.__init__() for instance initialization."
        super(Class_1,self).__init__()
        print "exiting Class_1.__init__()."

And now let's create an instance of Class_1

instance = Class_1()
# Meta_1.__call__() before creating an instance of <class '__main__.Class_1'>.
# Class_1.__new__() before creating an instance.
# Class_1.__new__() about to return instance.
# entering Class_1.__init__() for instance initialization.
# exiting Class_1.__init__().
# Meta_1.__call__() about to return instance.

The code above doesn't actually do anything other than logging the task and then delegating the actual work to the parent (ie keeping the default behavior). So with type being Meta_1 's parent class, we can imagine that this would be the pseudo implementation of type.__call__() :

class type:
    def __call__(cls, *args, **kwarg):

        # ... maybe a few things done to cls here

        # then we call __new__() on the class to create an instance
        instance = cls.__new__(cls, *args, **kwargs)

        # ... maybe a few things done to the instance here

        # then we initialize the instance with its __init__() method
        instance.__init__(*args, **kwargs)

        # ... maybe a few more things done to instance here

        # then we return it
        return instance

We can see that the metaclass's __call__() method is the one that's called first. It then delegates creation of the instance to the class's __new__() method and initialization to the instance's __init__() . It's also the one that ultimately returns the instance.

From the above it stems that the metaclass's __call__() is also given the opportunity to decide whether or not a call to Class_1.__new__() or Class_1.__init__() will eventually be made. Over the course of its execution it could actually return an object that hasn't been touched by either of these methods. Take for example this approach to the singleton pattern:

class Meta_2(type):
    singletons = {}

    def __call__(cls, *args, **kwargs):
        if cls in Meta_2.singletons:
            # we return the only instance and skip a call to __new__() 
            # and __init__()
            print ("{} singleton returning from Meta_2.__call__(), "
                   "skipping creation of new instance.".format(cls))
            return Meta_2.singletons[cls]

        # else if the singleton isn't present we proceed as usual
        print "Meta_2.__call__() before creating an instance."
        instance = super(Meta_2, cls).__call__(*args, **kwargs)
        Meta_2.singletons[cls] = instance
        print "Meta_2.__call__() returning new instance."
        return instance

class Class_2(object):

    __metaclass__ = Meta_2

    def __new__(cls, *args, **kwargs):
        print "Class_2.__new__() before creating instance."
        instance = super(Class_2, cls).__new__(cls)
        print "Class_2.__new__() returning instance."
        return instance

    def __init__(self, *args, **kwargs):
        print "entering Class_2.__init__() for initialization."
        super(Class_2, self).__init__()
        print "exiting Class_2.__init__()."

Let's observe what happens when repeatedly trying to create an object of type Class_2

a = Class_2()
# Meta_2.__call__() before creating an instance.
# Class_2.__new__() before creating instance.
# Class_2.__new__() returning instance.
# entering Class_2.__init__() for initialization.
# exiting Class_2.__init__().
# Meta_2.__call__() returning new instance.

b = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.

c = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.

a is b is c # True



私は、ONLampのメタクラスプログラミングの導入はよく書かれていると思います。すでに数年経っていますが、本当に良い紹介をしてくれます。

http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html

つまり、クラスはインスタンスの作成のための青写真であり、メタクラスはクラスの作成のための青写真です。 Pythonクラスでは、この動作を可能にするファーストクラスのオブジェクトである必要があることは容易にわかります。

私は自分自身を書いたことは一度もありませんでしたが、私はDjangoフレームワークでメタクラスの使い方の1つが見られると思います。 モデルクラスは、メタクラスアプローチを使用して、新しいモデルやフォームクラスを記述する宣言的スタイルを可能にします。 メタクラスがクラスを作成している間、すべてのメンバーがクラス自体をカスタマイズする可能性があります。

残っていることは、次のとおりです。メタクラスの種類がわからない場合、 必要としない確率は99%です。




メタクラスの用途の1つは、新しいプロパティとメソッドをインスタンスに自動的に追加することです。

たとえば、 Djangoモデルを見ると、その定義はちょっと混乱しています。 クラスプロパティのみを定義しているかのように見えます:

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

しかし、実行時に、Personオブジェクトはあらゆる種類の便利なメソッドで埋められます。 いくつかの素晴らしいメタクラスについてはsourceを参照してください。




Links