web-dev-qa-db-ja.com

「MetaClass」、「__ new __」、「cls」、「super」-メカニズムは正確には何ですか?

私はこれらのような投稿を読みました:

  1. Pythonのメタクラスとは何ですか?
  2. Pythonのメタクラスの(具体的な)ユースケースは何ですか?
  3. PythonのSuperは気の利いたものですが、使用できません

しかし、どういうわけか私は混乱しました。次のような多くの混乱:

いつ、なぜ私は次のようなことをしなければならないのですか?

# Refer link1
return super(MyType, cls).__new__(cls, name, bases, newattrs)

または

# Refer link2
return super(MetaSingleton, cls).__call__(*args, **kw)

または

# Refer link2
return type(self.__name__ + other.__name__, (self, other), {})

スーパーはどのように正確に機能しますか?

Link1のクラスレジストリとunregistryとは何ですか?また、どのように正確に機能しますか? (私はそれが singleton と関係があると思いました。私は間違っているかもしれません、Cのバックグラウンドからです。私のコーディングスタイルはまだ機能とOOの混合です)。

クラスのインスタンス化(サブクラス、メタクラス、スーパー、タイプ)とメソッド呼び出し(

metaclass->__new__, metaclass->__init__, super->__new__, subclass->__init__ inherited from metaclass

)適切にコメントされた作業コードを使用します(最初のリンクは非常に近いですが、clsキーワードとsuper(..)およびレジストリについては説明していません)。できれば多重継承の例。

追伸:Stack Overflowのフォーマットでテキストが変換されていたため、最後の部分をコードとして作成しましたmetaclass->__new__ to metaclass->new

28
JV.

OK、ここではかなりの数のコンセプトをミックスに取り入れました!私はあなたが持っている特定の質問のいくつかを引き出すつもりです。

一般に、Pythonの最後の数バージョンでこのトリッキーな領域に多くの変更が加えられたため、super、MRO、およびmetclassesの理解ははるかに複雑になります。

Python独自のドキュメント は非常に優れたリファレンスであり、完全に最新です。 IBMdeveloperWorksの記事 があります。これは紹介としては問題なく、よりチュートリアルベースのアプローチを採用していますが、5年前のものであり、話すのに多くの時間を費やしていることに注意してください。メタクラスへの古いスタイルのアプローチについて。

superは、オブジェクトのスーパークラスにアクセスする方法です。これは、主にPythonでの多重継承のために、(たとえば)Javaのsuperキーワードよりも複雑です。 Super Thoughd Harmful が説明しているように、super()を使用すると、スーパークラスのチェーンを暗黙的に使用することになります。その順序は/で定義されます。 メソッド解決順序 (MRO)。

(インスタンスではなく)クラスでmro()を呼び出すことにより、クラスのMROを簡単に確認できます。メタクラスはオブジェクトのスーパークラス階層にないことに注意してください。

Thomas 'メタクラスの説明 here は優れています:

メタクラスは、クラスのクラスです。クラスがクラスのインスタンスの動作を定義するように、メタクラスはクラスの動作を定義します。クラスはメタクラスのインスタンスです。

あなたが与える例では、これが起こっていることです:

  1. ___new___への呼び出しは、MROの次のことまでバブルアップされています。この場合、super(MyType, cls)typeに解決されます。 _type.__new___を呼び出すと、Pythonは、通常のインスタンス作成手順を完了します。

  2. この例では、メタクラスを使用してシングルトンを適用しています。彼はメタクラスの___call___をオーバーライドしているので、クラスインスタンスが作成されるたびにそれをインターセプトし、インスタンスの作成が既に存在する場合はそれをバイパスできます(_cls.instance_に格納されます)。メタクラスで___new___をオーバーライドするだけでは十分ではないことに注意してください。これは、クラスを作成するときにのみ呼び出されるためです。ただし、クラスで___new___をオーバーライドすると機能します。

  3. これは、クラスを動的に作成する方法を示しています。これは、提供されたクラスの名前を作成されたクラス名に追加し、それをクラス階層にも追加しているところです。

探しているコード例の種類は正確にはわかりませんが、メタクラス、継承、メソッド解決を示す簡単な例を次に示します。

_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(object):
    __metaclass__ = MyMeta
    def __init__(self):
        super(A, self).__init__()
        print "A init"

    def meth(self):
        print "A.meth"

class B(object):
    __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"

>>> c_obj = C()
meta: creating A (<type 'object'>,)
meta: creating B (<type 'object'>,)
meta: creating C (A, B)
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 "mro.py", line 38, in <module>
    c_obj.meta_meth()
AttributeError: 'C' object has no attribute 'meta_meth'
_
21
James Brady

これがより実用的な答えです。

それはめったに重要ではありません

  1. " Pythonのメタクラスとは "。結論として、typeはすべてのクラスのメタクラスです。これはほとんど実用的ではありません。

    class X(object):
        pass
    type(X) == type
    
  2. " Pythonのメタクラスの(具体的な)ユースケースは何ですか? "。結論。無し。

  3. " PythonのSuperは気の利いたものですが、使用できません "。興味深いメモですが、実用的な価値はほとんどありません。複雑な多重継承ネットワークを解決する必要はありません。多重継承の代わりに明示的なStrategy設計を使用することで、この問題の発生を簡単に防ぐことができます。

これが、過去7年間のPythonプログラミングの経験です。

  1. クラスには、私のクラスからobjectへの単純なチェーンを形成する1つ以上のスーパークラスがあります。

  2. 「クラス」の概念は、typeという名前のメタクラスによって定義されます。 「クラス」の概念を拡張したいと思うかもしれませんが、これまでのところ、実際には実現していません。一度もありません。 typeは常に正しいことをします。

  3. superの使用は、実際には非常にうまく機能します。これにより、サブクラスはそのスーパークラスに従うことができます。これらのメタクラスの例では、組み込みのメタクラスtypeを拡張しているため、たまたま表示されます。

    ただし、すべてのサブクラスの状況で、superを使用してスーパークラスを拡張します。

メタクラス

メタクラスの問題は次のとおりです。

  • すべてのオブジェクトには、その型定義、つまり「クラス」への参照があります。

  • classは、それ自体がオブジェクトでもあります。

  • したがって、タイプclassのオブジェクトには、そのタイプまたは「クラス」への参照があります。 「クラス」の「クラス」はメタクラスです。

「クラス」はC++ランタイムオブジェクトではないため、これはC++では発生しません。 Java、Smalltalk、Pythonで発生します。

メタクラスは、クラスオブジェクトの動作を定義します。

  • クラスとのやり取りの90%は、クラスに新しいオブジェクトを作成するように依頼することです。

  • 10%の確率で、クラスメソッドまたはクラス変数(C++では「静的」またはJava用語))を使用します。

クラスレベルのメソッドのユースケースをいくつか見つけました。クラス変数のユースケースはほとんどありません。オブジェクトの構築方法を変更する状況はこれまでありませんでした。

9
S.Lott