web-dev-qa-db-ja.com

`classmethod`とメタクラスメソッドの違いは何ですか?

Pythonでは、_@classmethod_デコレータを使用してクラスメソッドを作成できます。

_>>> class C:
...     @classmethod
...     def f(cls):
...             print(f'f called with cls={cls}')
...
>>> C.f()
f called with cls=<class '__main__.C'>
_

または、メタクラスで通常の(インスタンス)メソッドを使用することもできます。

_>>> class M(type):
...     def f(cls):
...             print(f'f called with cls={cls}')
...
>>> class C(metaclass=M):
...     pass
...
>>> C.f()
f called with cls=<class '__main__.C'>
_

C.f()の出力が示すように、これらの2つのアプローチは同様の機能を提供します。

_@classmethod_の使用とメタクラスでの通常のメソッドの使用の違いは何ですか?

12
user200783

あなたの例では、違いは、メタクラスとしてMが設定される他のいくつかのクラスにあります。

class M(type):
    def f(cls):
        pass

class C(metaclass=M):
    pass

class C2(metaclass=M):
    pass

C.f()
C2.f()
class M(type):
     pass

class C(metaclass=M):
     @classmethod
     def f(cls):
        pass

class C2(metaclass=M):
    pass

C.f()
# C2 does not have 'f'

ここにメタクラスの詳細があります メタクラスのいくつかの(具体的な)ユースケースは何ですか?

0
andole

@classmethodとMetaclassはどちらも異なります。

pythonのすべてがオブジェクトです。すべてのものはすべてのものを意味します。

メタクラスとは?

言ったようにすべてのものはオブジェクトです。クラスはオブジェクトでもあり、実際にはクラスは正式にメタクラスと呼ばれる他の不思議なオブジェクトのインスタンスです。指定されていない場合、pythonのデフォルトのメタクラスは「タイプ」です

デフォルトでは、定義されたすべてのクラスはタイプのインスタンスです。

クラスはメタクラスのインスタンスです

言及された行動を理解することはほとんど重要ではありません

  • クラスはメタクラスのインスタンスなので。
  • インスタンス化されたすべてのオブジェクトと同様に、オブジェクト(インスタンス)もクラスから属性を取得します。クラスはメタクラスから属性を取得します

次のコードを検討する

class Meta(type):
    def foo(self):
        print(f'foo is called self={self}')
        print('{} is instance of {}: {}'.format(self, Meta, isinstance(self, Meta)))

class C(metaclass=Meta):
    pass

C.foo()

どこ、

  • クラスCはクラスMetaのインスタンスです
  • 「クラスC」は「クラスメタ」のインスタンスであるクラスオブジェクト
  • 他のオブジェクト(インスタンス)と同様に、「クラスC」は、「クラスメタ」クラスで定義された属性/メソッドにアクセスできます。
  • したがって、 "C.foo()"をデコードします。 「C」は「Meta」のインスタンスであり、「foo」は「C」である「Meta」のインスタンスを介したメソッド呼び出しです。
  • メソッド「foo」の最初の引数は、「classmethod」とは異なり、クラスではなくインスタンスへの参照です

「クラスC」が「クラスメタ」のインスタンスであるかのように確認できます。

  isinstance(C, Meta)

クラスメソッドとは何ですか?

Pythonメソッドはバインドされていると言われています。 pythonは、メソッドをインスタンスのみで呼び出す必要があるという制限を課します。インスタンスを作成せずに、インスタンスなしで(Javaの静的メンバーのように)クラスから直接メソッドを呼び出す場合があります。任意のインスタンス。デフォルトでは、メソッドを呼び出すにはインスタンスが必要です。回避策としてpythonは、インスタンスの代わりにクラスに特定のメソッドをバインドする組み込み関数classmethodを提供します。

クラスメソッドはクラスにバインドされているため。インスタンス(自己)ではなくクラス自体への参照である少なくとも1つの引数を取ります

組み込み関数/デコレータクラスメソッドが使用されている場合。最初の引数はインスタンスではなくクラスへの参照になります

class ClassMethodDemo:
    @classmethod
    def foo(cls):
        print(f'cls is ClassMethodDemo: {cls is ClassMethodDemo}')

「classmethod」を使用したので、次のようにインスタンスを作成せずにメソッド「foo」を呼び出します

ClassMethodDemo.foo()

上記のメソッド呼び出しはTrueを返します。最初の引数clsは確かに「ClassMethodDemo」への参照であるため

概要:

  • Classmethodの最初の引数である「クラス(従来はclsと呼ばれていました)自体への参照」
  • メタクラスのメソッドはクラスメソッドではありません。メタクラスのメソッドは、「クラスではなくインスタンス(伝統的に自己と呼ばれる)への参照」である最初の引数を受け取ります
0
neotam