いつ@classmethodを使用する必要があり、いつdef method(self)を使用する必要がありますか?


92

これまで使用したことのないDjangoアプリを統合しているときに、クラスで関数を定義するために使用される2つの異なる方法を見つけました。作者は両方とも非常に意図的に使用しているようです。最初のものは私自身がよく使うものです:

class Dummy(object):

    def some_function(self,*args,**kwargs):
        do something here
        self is the class instance

もう1つは、私が使用しないものです。これは主に、いつ使用するのか、何のために使用するのかがわからないためです。

class Dummy(object):

    @classmethod
    def some_function(cls,*args,**kwargs):
        do something here
        cls refers to what?

Pythonのドキュメントでは、classmethodデコレータは次の文で説明されています。

クラスメソッドは、インスタンスメソッドがインスタンスを受け取るのと同じように、暗黙の最初の引数としてクラスを受け取ります。

したがって、私clsDummyそれ自体を参照していると思います(classインスタンスではなく、)。私はいつでもこれを行うことができたので、なぜこれが存在するのか正確には理解していません:

type(self).do_something_with_the_class

これは明確にするためだけですか、それとも私は最も重要な部分を見逃しましたか?それなしでは実行できない不気味で魅力的なことですか?

回答:


71

あなたの推測は正しいです-あなたはsがどのように機能 するを理解していますclassmethod

その理由は、これらのメソッドをインスタンスまたはクラスの両方で呼び出すことができるためです(どちらの場合も、クラスオブジェクトは最初の引数として渡されます)。

class Dummy(object):

    @classmethod
    def some_function(cls,*args,**kwargs):
        print cls

#both of these will have exactly the same effect
Dummy.some_function()
Dummy().some_function()

インスタンスでのこれらの使用について:インスタンスでclassmethodを呼び出すには、少なくとも2つの主な使用法があります。

  1. self.some_function()その呼び出しが発生するクラスではなくsome_function、実際のタイプののバージョンselfを呼び出します(クラスの名前が変更された場合は注意する必要はありません)。そして
  2. some_functionいくつかのプロトコルを実装するために必要であるが、クラスオブジェクトのみを呼び出すのに役立つ場合。

との違いstaticmethod:インスタンスデータにアクセスしないメソッドを定義する別の方法があります。これはと呼ばれstaticmethodます。これにより、暗黙の最初の引数をまったく受け取らないメソッドが作成されます。したがって、呼び出されたインスタンスまたはクラスに関する情報は渡されません。

In [6]: class Foo(object): some_static = staticmethod(lambda x: x+1)

In [7]: Foo.some_static(1)
Out[7]: 2

In [8]: Foo().some_static(1)
Out[8]: 2

In [9]: class Bar(Foo): some_static = staticmethod(lambda x: x*2)

In [10]: Bar.some_static(1)
Out[10]: 2

In [11]: Bar().some_static(1)
Out[11]: 2

私が見つけた主な用途は、既存の関数(を受け取ることを期待しないself)をクラス(またはオブジェクト)のメソッドに適合させることです。


2
いいですね:答えがどのように分割されるのが好きです-なぜ。私が今それを手に入れている限り、@ classmethodはインスタンスを必要とせずに関数にアクセスすることを許可します。これはまさに私が探していたものです、ありがとう。
マルエ

1
@marcin真のダックタイピングはそれに他の次元を与えます。それはself.foo()、あるべき時のようなものを書かないことについてでしたBar.foo()
Voo 2012年

5
@Voo実際にself.foo()self、独自のを実装するサブクラスのインスタンスである可能性があるため、推奨されますfoo
Marcin 2012年

1
@Marcinこれはあなたが何を達成したいかによると思います。しかし、私はあなたの主張を理解します。
2012年

1
、のように別のラムダを使用する必要があるためBar、実際に呼び出さ1+1 == 2 == 1*2れた結果から判断することはできませんBar().static_method
ジョージV.ライリー2017年

0

基本的に、メソッドの定義が変更またはオーバーライドされないことに気付いた場合は、@ classmethodを使用する必要があります。

追加:理論的には、クラスメソッドはオブジェクトメソッドよりも高速です。これは、インスタンス化する必要がなく、必要なメモリが少ないためです。


-3

デコレータ@classmethodを追加すると、そのメソッドをJavaまたはC ++の静的メソッドとして作成することになります。(静的メソッドは私が推測する一般的な用語です;))Pythonには@staticmethodもあります。classmethodとstaticmethodの違いは、引数またはクラス名自体を使用してクラスまたは静的変数にアクセスできるかどうかです。

class TestMethod(object):
    cls_var = 1
    @classmethod
    def class_method(cls):
        cls.cls_var += 1
        print cls.cls_var

    @staticmethod
    def static_method():
        TestMethod.cls_var += 1
        print TestMethod.cls_var
#call each method from class itself.
TestMethod.class_method()
TestMethod.static_method()

#construct instances
testMethodInst1 = TestMethod()    
testMethodInst2 = TestMethod()   

#call each method from instances
testMethodInst1.class_method()
testMethodInst2.static_method()

これらのクラスはすべて、cls.cls_varを1増やして出力します。

そして、これらのクラスで構築された同じスコープまたはインスタンスで同じ名前を使用するすべてのクラスは、それらのメソッドを共有します。TestMethod.cls_varは1つだけであり、TestMethod.class_method()、TestMethod.static_method()も1つだけです。

そして重要な質問です。これらの方法が必要な理由。

classmethodまたはstaticmethodは、そのクラスをファクトリとして作成する場合、またはクラスを1回だけ初期化する必要がある場合に役立ちます。ファイルを一度開いて、feedメソッドを使用してファイルを1行ずつ読み取るようなものです。


2
(a)静的メソッドは別のものです。(b)classmethodsはすべてのクラスで共有されるわけではありません。
Marcin

@Marcinは、私の不明確な定義などを知らせてくれてありがとう。
ライアンキム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.