staticmethodとclassmethodの違い


3582

飾ら機能の違いは何です@staticmethodが飾られ、もう一方は@classmethod


11
静的メソッドは、清潔さのために、Pythonのモジュールレベルの関数としてより適切な場合があります。モジュール関数を使用すると、必要な関数だけをインポートして、不要な「。」を防ぐのが簡単になります。構文(私はObjective-Cを見ています)。クラスメソッドは、ポリモーフィズムと組み合わせて「ファクトリーパターン」関数を作成できるため、より多くの用途があります。これは、クラスメソッドがクラスを暗黙的なパラメーターとして受け取るためです。
FistOfFury 2017

27
tl; dr >>通常のメソッドと比較すると、静的メソッドとクラスメソッドにもクラスを使用してアクセスできますが、クラスメソッドとは異なり、静的メソッドは継承によって不変です。
imsrgadich

4
このトピックに関するレイモンドヘッティンガーの関連講演:youtube.com/watch
v

より正確なyoutube.com/watch?v=HTLu2DFOdTg&feature=youtu.be&t=2689必要なのは、代替コンストラクタのクラスメソッドだけです。それ以外の場合は、staticmethodを使用して、classmethodのようなclsの代わりに、なんとなくより有益な実際の "CLASSNAME"でクラス属性(。/ドットを介して)にアクセスできます
Robert Nowak

回答:


3137

お知らせの呼び出しシグネチャの違いを:たぶん、サンプルコードのビットは助けるfooclass_foostatic_foo

class A(object):
    def foo(self, x):
        print "executing foo(%s, %s)" % (self, x)

    @classmethod
    def class_foo(cls, x):
        print "executing class_foo(%s, %s)" % (cls, x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)" % x    

a = A()

以下は、オブジェクトインスタンスがメソッドを呼び出す通常の方法です。オブジェクトインスタンスはa、最初の引数として暗黙的に渡されます。

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)

classmethodsでは、オブジェクトインスタンスのクラスが最初の引数としてではなく暗黙的に渡されますself

a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

class_fooクラスを使用して呼び出すこともできます。実際、何かをクラスメソッドとして定義する場合、それはおそらくクラスインスタンスからではなくクラスからそれを呼び出すつもりだからです。A.foo(1)TypeErrorが発生しますが、問題なくA.class_foo(1)機能します。

A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

人々がクラスメソッドに使用した1つの用途は、継承可能な代替コンストラクタを作成することです。


staticmethodsでは、self(オブジェクトインスタンス)もcls(クラス)も暗黙的に最初の引数として渡されません 。これらは、インスタンスまたはクラスから呼び出すことができることを除いて、単純な関数のように動作します。

a.static_foo(1)
# executing static_foo(1)

A.static_foo('hi')
# executing static_foo(hi)

静的メソッドは、クラスとクラスとの論理的な接続を持つ関数をグループ化するために使用されます。


fooは単なる関数ですが、呼び出すa.fooと関数を取得するだけでなく、オブジェクトインスタンスaが関数の最初の引数としてバインドされた、「部分的に適用された」バージョンの関数を取得します。foo引数が2つ必要ですが、必要な引数a.fooは1つだけです。

aにバインドされていfooます。これが、以下の「バインド」という用語の意味するところです。

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>

を使用するとa.class_fooaはにバインドされclass_fooず、クラスAがにバインドされclass_fooます。

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

ここでは、staticmethodを使用して、それがメソッドであっても、a.static_foo引数がバインドされていない適切なole関数を返します。static_foo1つの引数を期待し、 a.static_fooあまりにも1つの引数を期待しています。

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

そしてもちろん、代わりにstatic_fooクラスで呼び出すときにも同じことが起こりますA

print(A.static_foo)
# <function static_foo at 0xb7d479cc>

182
staticmethodを使用する際の注意点がわかりません。単純なクラス外関数を使用できます。
Alcott、2011

372
@Alcott:関数はクラスに論理的に属しているため、関数をクラスに移動することができます。Pythonソースコード(例:multiprocessing、turtle、dist-packages)では、モジュールの名前空間からシングルアンダースコアの「プライベート」関数を「隠す」ために使用されます。ただし、その使用はほんの数個のモジュールに非常に集中しています-おそらくそれが主に文体的なものであることを示しています。私はこれの例を見つけることができませんでし@staticmethodたが、サブクラスによってオーバーライドされることでコードを整理するのに役立つかもしれません。それがなければ、モジュールの名前空間に関数のバリエーションが浮かんでいるでしょう。
unutbu '19

15
... インスタンス、クラス、または静的メソッドをどこどのように使用するかについての説明とともに。あなたはそれについて一言も言わなかったが、OPはそれについて尋ねなかった。
MestreLion、2012年

106
@Alcott:unutbuが言ったように、静的メソッドは編成/スタイルの機能です。モジュールには多くのクラスがあり、一部のヘルパー関数は特定のクラスに論理的に結び付けられ、他のクラスには結び付けられない場合があるため、多くの「自由関数」でモジュールを「汚染」しないことが理にかなっており、静的関数を使用する方が良い「関連している」ことを示すために、コード内でクラスと関数の
定義

4
もう1つの用途@staticmethod-あなたはそれを使用して、残骸を取り除くことができます。私はPythonでプログラミング言語を実装しています。ライブラリ定義関数は静的executeメソッドを使用します。ユーザー定義関数はインスタンス引数(つまり、関数本体)を必要とします。このデコレータは、PyCharmインスペクターの「未使用のパラメーターの自己」警告を排除します。
tehwalrus

799

staticmethodは、それがコールされたクラスまたはインスタンスについて何も知らない方法です。渡された引数を取得するだけで、暗黙の最初の引数はありません。これは基本的にPythonでは役に立たない-静的メソッドの代わりにモジュール関数を使用するだけでよい。

クラスメソッド、一方で、最初の引数として、それがコールされたクラス、またはそれがコールされたインスタンスのクラスを渡される方法です。これは、メソッドをクラスのファクトリーにする場合に便利です。最初の引数として呼び出された実際のクラスを取得するため、サブクラスが関係する場合でも、常に適切なクラスをインスタンス化できます。たとえばdict.fromkeys()、クラスメソッドがサブクラスで呼び出されたときにサブクラスのインスタンスを返す方法を確認します。

>>> class DictSubclass(dict):
...     def __repr__(self):
...         return "DictSubclass"
... 
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>> 

715
staticmethodは役に立たないわけではありません-これは関数をクラスに入れる方法です(論理的にはクラスに属しているため)一方で、クラスへのアクセスを必要としないことを示しています。
Tony Meyer、

136
したがって、「基本的に」役に立たないだけです。このような編成と依存性注入は、静的メソッドの有効な使用法ですが、JavaのようなクラスではなくモジュールがPythonのコード編成の基本要素であるため、その使用法と有用性はほとんどありません。
Thomas Wouters

40
クラスまたはそのインスタンスのいずれとも関係がない場合、クラス内でメソッドを定義することの論理は何ですか?
Ben James

107
多分相続のために?静的メソッドは、インスタンスメソッドやクラスメソッドと同じように継承およびオーバーライドでき、ルックアップは(Javaとは異なり)期待どおりに機能します。静的メソッドは、クラスまたはインスタンスのどちらで呼び出されても、実際には静的に解決されないため、クラスメソッドと静的メソッドの唯一の違いは、暗黙的な最初の引数です。
haridsv 2010

80
また、より明確な名前空間を作成し、関数がクラスと関係があることを理解しやすくします。
Imbrondir 2011

149

基本的に@classmethod、最初の引数が(クラスインスタンスで@staticmethodはなく)呼び出し元のクラスであるメソッドに、暗黙の引数がないメソッドを作成します。


103

公式のPythonドキュメント:

@classmethod

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

class C:
    @classmethod
    def f(cls, arg1, arg2, ...): ... 

@classmethodフォームは、関数である デコレータ -で関数定義の説明を参照してください関数の定義の詳細について。

クラス(などC.f())またはインスタンス(など)で呼び出すことができますC().f()。クラス以外のインスタンスは無視されます。派生クラスに対してクラスメソッドが呼び出された場合、派生クラスオブジェクトは暗黙の最初の引数として渡されます。

クラスメソッドは、C ++またはJavaの静的メソッドとは異なります。それらが必要な場合はstaticmethod()、このセクションを参照してください。

@staticmethod

静的メソッドは暗黙の最初の引数を受け取りません。静的メソッドを宣言するには、次のイディオムを使用します。

class C:
    @staticmethod
    def f(arg1, arg2, ...): ... 

@staticmethodフォームは、関数である デコレータ -で関数定義の説明を参照してください関数の定義の詳細について。

クラス(などC.f())またはインスタンス(など)で呼び出すことができますC().f()。クラス以外のインスタンスは無視されます。

Pythonの静的メソッドは、JavaまたはC ++にあるものと似ています。より高度な概念についてはclassmethod()、このセクションを参照してください 。


ドキュメントにエラーはありませんか?staticmethodにすべきではありません:「インスタンスとそのクラスはどちらも無視されます。」「インスタンスはそのクラスを除いて無視されます」の代わりに?
mirek

カットアンドペーストのエラーの可能性がありますが、厳密に言えば、クラスを無視すると、クラスのメソッドを呼び出すことができません。
アーロンベントレー

76

ここでは、この質問への短い記事があります

@staticmethod関数は、クラス内で定義された関数にすぎません。最初にクラスをインスタンス化せずに呼び出すことができます。その定義は継承によって不変です。

@classmethod関数もクラスをインスタンス化せずに呼び出すことができますが、その定義は継承によって、親クラスではなくサブクラスに従います。@classmethod関数の最初の引数は常にcls(クラス)でなければならないためです。


1
それは、静的メソッドを使用することで常に親クラスにバインドされ、クラスメソッドを使用すると、クラスメソッドを宣言したクラス(この場合はサブクラス)がバインドされることを意味しますか?
モハングラティ

7
いいえ。staticmethodを使用すると、まったく拘束されません。暗黙の最初のパラメーターはありません。classmethodを使用すると、メソッドを呼び出したクラス(クラスで直接呼び出した場合)またはメソッドを呼び出したインスタンスのクラス(インスタンスで呼び出した場合)の暗黙の最初のパラメーターとして取得します。
マットアンダーソン、

6
少し拡張すると、クラスを最初の引数として使用することで、クラスメソッドは他のクラスの属性とメソッドに直接アクセスできますが、静的メソッドはそうではありません(そのためにMyClass.attrをハードコードする必要があります)
MestreLion

「その定義は継承によって不変です。」Pythonでは意味がありません。静的メソッドをうまくオーバーライドできます。
cz

68

使用するかどうかを決定するために、@staticmethodまたは@classmethod、あなたのメソッドの内部で見ています。メソッドがクラス内の他の変数/メソッドにアクセスする場合は、@classmethodを使用します。一方、メソッドがクラスの他の部分に触れない場合は、@ staticmethodを使用します。

class Apple:

    _counter = 0

    @staticmethod
    def about_apple():
        print('Apple is good for you.')

        # note you can still access other member of the class
        # but you have to use the class instance 
        # which is not very nice, because you have repeat yourself
        # 
        # For example:
        # @staticmethod
        #    print('Number of apples have been juiced: %s' % Apple._counter)
        #
        # @classmethod
        #    print('Number of apples have been juiced: %s' % cls._counter)
        #
        #    @classmethod is especially useful when you move your function to other class,
        #       you don't have to rename the class reference 

    @classmethod
    def make_apple_juice(cls, number_of_apples):
        print('Make juice:')
        for i in range(number_of_apples):
            cls._juice_this(i)

    @classmethod
    def _juice_this(cls, apple):
        print('Juicing %d...' % apple)
        cls._counter += 1

classmethodとcls._counterとstaticmethodとApple._counterの利点は何ですか
Robert Nowak

1
cls._counterまだだろうcls._counterコードは別のクラスに入れている、またはクラス名が変更されても。クラスApple._counter固有ですApple。別のクラスの場合、またはクラス名が変更された場合は、参照されるクラスを変更する必要があります。
kiamlaluno

53

Pythonの@staticmethodと@classmethodの違いは何ですか?

この疑似コードのようなPythonコードを見たことがあるかもしれません。これは、さまざまなメソッドタイプのシグネチャを示し、それぞれを説明するdocstringを提供します。

class Foo(object):

    def a_normal_instance_method(self, arg_1, kwarg_2=None):
        '''
        Return a value that is a function of the instance with its
        attributes, and other arguments such as arg_1 and kwarg2
        '''

    @staticmethod
    def a_static_method(arg_0):
        '''
        Return a value that is a function of arg_0. It does not know the 
        instance or class it is called from.
        '''

    @classmethod
    def a_class_method(cls, arg1):
        '''
        Return a value that is a function of the class and other arguments.
        respects subclassing, it is called with the class it is called from.
        '''

通常のインスタンスメソッド

まず説明しa_normal_instance_methodます。これは、正確に「インスタンスメソッド」と呼ばれます。インスタンスメソッドが使用される場合、それは部分関数として使用されます(合計関数ではなく、ソースコードで表示されるときにすべての値に対して定義されます)。つまり、使用される場合、最初の引数はインスタンスのインスタンスとして事前定義されます。指定されたすべての属性を持つオブジェクト。バインドされているオブジェクトのインスタンスがあり、オブジェクトのインスタンスから呼び出す必要があります。通常、インスタンスのさまざまな属性にアクセスします。

たとえば、これは文字列のインスタンスです。

', '

joinこの文字列でインスタンスメソッドを使用して別の反復可能オブジェクトを結合する場合、それは明らかに反復可能リストの関数であることに加えて、インスタンスの関数です['a', 'b', 'c']

>>> ', '.join(['a', 'b', 'c'])
'a, b, c'

バインドされたメソッド

インスタンスメソッドは、後で使用するためにドット付きルックアップを介してバインドできます。

たとえば、これはstr.joinメソッドを':'インスタンスにバインドします。

>>> join_with_colons = ':'.join 

後でこれを、最初の引数がすでにバインドされている関数として使用できます。このように、インスタンスの部分的な関数のように機能します。

>>> join_with_colons('abcde')
'a:b:c:d:e'
>>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF'])
'FF:FF:FF:FF:FF:FF'

静的メソッド

静的メソッドは、インスタンスを引数として取りませ

これは、モジュールレベルの関数によく似ています。

ただし、モジュールレベルの関数はモジュール内に存在し、それが使用される他の場所に特別にインポートされる必要があります。

ただし、オブジェクトにアタッチされている場合は、インポートと継承によってもオブジェクトに追随します。

静的メソッドの例は、Python 3 str.maketransstringモジュールから移動したです。これにより、変換テーブルがによる使用に適したものになりますstr.translate。以下に示すように、文字列のインスタンスから使用すると、かなりばかげているように見えstringますが、モジュールから関数をインポートするのはかなり不格好です。str.maketrans

# demonstrate same function whether called from instance or not:
>>> ', '.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}
>>> str.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}

Python 2では、この関数を、ますます使いにくくなる文字列モジュールからインポートする必要があります。

>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'

クラスメソッド

クラスメソッドは、暗黙的な最初の引数を取るという点でインスタンスメソッドに似ていますが、インスタンスを取る代わりに、クラスを取ります。多くの場合、これらはセマンティックの使用法を改善するための代替コンストラクタとして使用され、継承をサポートします。

組み込みクラスメソッドの最も標準的な例はdict.fromkeysです。これは、dictの代替コンストラクターとして使用されます(キーが何であるかを知っていて、それらのデフォルト値が必要な場合に適しています)。

>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}

dictをサブクラス化するときは、同じコンストラクタを使用して、サブクラスのインスタンスを作成できます。

>>> class MyDict(dict): 'A dict subclass, use to demo classmethods'
>>> md = MyDict.fromkeys(['a', 'b', 'c'])
>>> md
{'a': None, 'c': None, 'b': None}
>>> type(md)
<class '__main__.MyDict'>

参照してくださいパンダソースコードの代替コンストラクタの他の同様の例については、とにも公式Pythonドキュメントを参照してくださいclassmethodstaticmethod


43

C ++、Java、Pythonのプログラミング言語の学習を始めたので、それぞれの簡単な使用法を理解するまで、この質問にもかなり悩みました。

クラスメソッド: JavaやC ++とは異なり、Pythonにはコンストラクタのオーバーロードがありません。これを実現するには、を使用できますclassmethod。次の例はこれを説明します

我々は持って考えてみましょうPerson二つの引数を取るクラスfirst_namelast_nameのインスタンスを作成しますPerson

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

さて、単一の名前のみを使用してクラスを作成する必要がある場合、だけでfirst_name、Pythonではこのようなことはできません。

オブジェクト(インスタンス)を作成しようとすると、エラーが発生します。

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def __init__(self, first_name):
        self.first_name = first_name

ただし、@classmethod以下のように使用して同じことを達成できます

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    @classmethod
    def get_person(cls, first_name):
        return cls(first_name, "")

静的メソッド:これはかなり単純で、インスタンスやクラスにバインドされておらず、クラス名を使用して呼び出すだけです。

上記の例でfirst_name、20文字を超えない検証が必要であるとしましょう。これは簡単に行うことができます。

@staticmethod  
def validate_name(name):
    return len(name) <= 20

あなたは単に使用して呼び出すことができます class name

Person.validate_name("Gaurang Shah")

2
古い投稿ですが、1つまたは2つの引数を受け入れるコンストラクターを実現するためのよりPython的な方法def __init__(self, first_name, last_name="")は、classmethodの代わりに使用しget_personます。この場合も結果はまったく同じになります。
akarilimano

31

より良い質問は、「@ classmethodと@staticmethodをいつ使用しますか?」

@classmethodを使用すると、クラス定義に関連付けられているプラ​​イベートメンバーに簡単にアクセスできます。これは、シングルトン、または作成されたオブジェクトのインスタンスの数を制御するファクトリクラスを実行するための優れた方法です。

@staticmethodを使用すると、パフォーマンスがわずかに向上しますが、クラス外でスタンドアロン関数として実現できないクラス内で静的メソッドを生産的に使用することはまだ見ていません。


31

@decoratorsはpython 2.4で追加されました。Python<2.4を使用している場合は、classmethod()およびstaticmethod()関数を使用できます。

たとえば、ファクトリメソッド(取得する引数に応じてクラスの異なる実装のインスタンスを返す関数)を作成する場合は、次のようにします。

class Cluster(object):

    def _is_cluster_for(cls, name):
        """
        see if this class is the cluster with this name
        this is a classmethod
        """ 
        return cls.__name__ == name
    _is_cluster_for = classmethod(_is_cluster_for)

    #static method
    def getCluster(name):
        """
        static factory method, should be in Cluster class
        returns a cluster object for the given name
        """
        for cls in Cluster.__subclasses__():
            if cls._is_cluster_for(name):
                return cls()
    getCluster = staticmethod(getCluster)

また、これはクラスメソッドと静的メソッドを使用する良い例であることに注意してください。静的メソッドはクラスClusterを内部で使用するため、明らかにクラスに属しています。classmethodはクラスに関する情報のみを必要とし、オブジェクトのインスタンスは必要ありません。

_is_cluster_forメソッドをクラスメソッドにするもう1つの利点は、サブクラスが実装を変更することを決定できることです。これは、かなり汎用的であり、複数のタイプのクラスターを処理できるため、クラスの名前をチェックするだけでは不十分です。


28

静的メソッド:

  • 自己引数のない単純な関数。
  • クラス属性に取り組みます。インスタンス属性ではありません。
  • クラスとインスタンスの両方から呼び出すことができます。
  • 組み込み関数staticmethod()を使用してそれらを作成します。

静的メソッドの利点:

  • クラススコープで関数名をローカライズします
  • 関数コードを使用場所に近づけます
  • 各メソッドを特別にインポートする必要がないため、モジュールレベルの関数よりもインポートがより便利です。

    @staticmethod
    def some_static_method(*args, **kwds):
        pass

クラスメソッド:

  • クラス名として最初の引数を持つ関数。
  • クラスとインスタンスの両方から呼び出すことができます。
  • これらは、組み込みのclassmethod関数で作成されます。

     @classmethod
     def some_class_method(cls, *args, **kwds):
         pass

22

@staticmethodメソッド記述子としてのデフォルト関数を無効にするだけです。classmethodは、所有するクラスへの参照を最初の引数として渡すコンテナ呼び出し可能オブジェクトで関数をラップします。

>>> class C(object):
...  pass
... 
>>> def f():
...  pass
... 
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>

実際にclassmethodは、ランタイムオーバーヘッドがありますが、所有するクラスにアクセスできます。または、メタクラスを使用して、クラスメソッドをそのメタクラスに配置することをお勧めします。

>>> class CMeta(type):
...  def foo(cls):
...   print cls
... 
>>> class C(object):
...  __metaclass__ = CMeta
... 
>>> C.foo()
<class '__main__.C'>

1
このメタクラスの短所の1つは、インスタンスで直接クラスメソッドを呼び出せないことです。c = C(); c.foo()AttributeErrorを発生させますtype(c).foo()。そうする必要があります。これも機能と考えられるかもしれませんが、なぜそうしたいのか、私には思いつきません。
アーロンホール

20

Pythonで静的メソッド、クラスメソッド、または抽象メソッドを使用する方法に関する決定的なガイドは、このトピックへの良いリンクの1つであり、次のように要約します。

@staticmethodfunctionは、クラス内で定義された関数にすぎません。最初にクラスをインスタンス化せずに呼び出すことができます。その定義は継承によって不変です。

  • Pythonはオブジェクトのバインドされたメソッドをインスタンス化する必要はありません。
  • コードを読みやすくし、オブジェクト自体の状態には依存しません。

@classmethod関数はクラスをインスタンス化せずに呼び出すこともできますが、その定義は継承によって親クラスではなくサブクラスに従い、サブクラスによってオーバーライドできます。これは、@classmethod関数の最初の引数は常にcls(クラス)でなければならないためです。

  • ファクトリーメソッドたとえば、ある種の前処理を使用してクラスのインスタンスを作成するために使用される。
  • 静的メソッドを呼び出す静的メソッド:静的メソッドをいくつかの静的メソッドに分割する場合は、クラス名をハードコーディングせずに、クラスメソッドを使用する必要があります。

おかげで@zangw-静的関数の継承された不変性は、それが思われる主な違いです
hard_working_ant

18

最初の引数のみが異なります

  • 通常のメソッド:現在のオブジェクト追加の)最初の引数として自動的に渡された場合
  • classmethod:現在のオブジェクトのクラスは(追加の)fist引数として自動的に渡されます
  • staticmethod:追加の引数は自動的に渡されません。関数に渡したのは、取得したものです。

さらに詳細に...

通常の方法

オブジェクトのメソッドが呼び出されると、self最初の引数として自動的に追加の引数が与えられます。つまり、方法

def f(self, x, y)

2つの引数を指定して呼び出す必要があります。self自動的に渡され、それはオブジェクト自体です

クラスメソッド

メソッドが装飾されているとき

@classmethod
def f(cls, x, y)

自動的に提供される引数はではありません self self

静的メソッド

メソッドが装飾されているとき

@staticmethod
def f(x, y)

メソッドに、自動引数はまったく与えられませ。呼び出されたパラメーターのみが指定されます。

使用法

  • classmethod 主に代替コンストラクタに使用されます。
  • staticmethodオブジェクトの状態は使用しません。これは、クラスの外部の関数である可能性があります。同様の機能を持つ関数をグループ化するためにクラス内にのみ配置します(たとえば、JavaのMathクラス静的メソッドなど)
class Point
    def __init__(self, x, y):
        self.x = x
        self.y = y

    @classmethod
    def frompolar(cls, radius, angle):
        """The `cls` argument is the `Point` class itself"""
        return cls(radius * cos(angle), radius * sin(angle))

    @staticmethod
    def angle(x, y):
        """this could be outside the class, but we put it here 
just because we think it is logically related to the class."""
        return atan(y, x)


p1 = Point(3, 2)
p2 = Point.frompolar(3, pi/4)

angle = Point.angle(3, 2)

17

最初に@classmethodで装飾されたメソッドと@staticmethodで装飾されたメソッドの類似性を教えてみましょう。

類似性:どちらも、クラスインスタンスだけでなく、クラス自体で呼び出すことができます。したがって、ある意味でこれらは両方ともClassのメソッドです。

違い:クラスメソッドはクラス自体を最初の引数として受け取りますが、静的メソッドは受け取りません。

したがって、静的メソッドは、ある意味ではクラス自体にバインドされておらず、関連する機能を備えている可能性があるという理由だけでそこにぶら下がっています。

>>> class Klaus:
        @classmethod
        def classmthd(*args):
            return args

        @staticmethod
        def staticmthd(*args):
            return args

# 1. Call classmethod without any arg
>>> Klaus.classmthd()  
(__main__.Klaus,)  # the class gets passed as the first argument

# 2. Call classmethod with 1 arg
>>> Klaus.classmthd('chumma')
(__main__.Klaus, 'chumma')

# 3. Call staticmethod without any arg
>>> Klaus.staticmthd()  
()

# 4. Call staticmethod with 1 arg
>>> Klaus.staticmthd('chumma')
('chumma',)

11

staticmethodとclassmethodに関するもう1つの考慮事項は、継承です。次のクラスがあるとします。

class Foo(object):
    @staticmethod
    def bar():
        return "In Foo"

次にbar()、子クラスでオーバーライドします。

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"

これは機能しbar()ますが、子クラス(Foo2)の実装では、そのクラスに固有の機能を利用できなくなりました。たとえば、次の実装で使用したいFoo2というメソッドがあったとmagic()します。Foo2bar()

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"
    @staticmethod
    def magic():
        return "Something useful you'd like to use in bar, but now can't" 

この問題を回避するには、ここでコールするだろうFoo2.magic()bar()はなく、(の名前ならば、あなたは自分自身を繰り返しているFoo2変更は、あなたがその更新することを忘れないでくださいする必要がありますbar()方法を)。

私にとって、これはオープン/クローズの原則に対するわずかな違反です。なぜなら、決定がFoo派生クラスの共通コードをリファクタリングする機能に影響を与えているからです(つまり、拡張に対してあまりオープンではありません)。もし私たちが大丈夫bar()だったらclassmethod

class Foo(object):
    @classmethod
    def bar(cls):
        return "In Foo"

class Foo2(Foo):
    @classmethod
    def bar(cls):
        return "In Foo2 " + cls.magic()
    @classmethod
    def magic(cls):
        return "MAGIC"

print Foo2().bar()

与える: In Foo2 MAGIC


7

基本的な違いを例を挙げて説明します。

class A(object):
    x = 0

    def say_hi(self):
        pass

    @staticmethod
    def say_hi_static():
        pass

    @classmethod
    def say_hi_class(cls):
        pass

    def run_self(self):
        self.x += 1
        print self.x # outputs 1
        self.say_hi()
        self.say_hi_static()
        self.say_hi_class()

    @staticmethod
    def run_static():
        print A.x  # outputs 0
        # A.say_hi() #  wrong
        A.say_hi_static()
        A.say_hi_class()

    @classmethod
    def run_class(cls):
        print cls.x # outputs 0
        # cls.say_hi() #  wrong
        cls.say_hi_static()
        cls.say_hi_class()

1-初期化せずに静的メソッドとクラスメソッドを直接呼び出すことができます

# A.run_self() #  wrong
A.run_static()
A.run_class()

2-静的メソッドは自己メソッドを呼び出すことはできませんが、他の静的メソッドおよびクラスメソッドを呼び出すことはできます

3-静的メソッドはクラスに属し、オブジェクトをまったく使用しません。

4-クラスメソッドは、オブジェクトではなくクラスにバインドされます。


広告2:よろしいですか?staticmethodはどのようにclassmethodを呼び出すことができますか?(クラスへの)参照はありません。
mirek

7

@classmethod:複数のユーザーによるレコードの更新のように、そのクラスで作成されたすべてのインスタンスへの共有グローバルアクセスを作成するために使用できます。 )

@静的メソッド:関連付けられているクラスまたはインスタンスとは関係ありませんが、読みやすさのために静的メソッドを使用できます


5

次の違いを検討してください。

Class A:
    def foo():  # no self parameter, no decorator
        pass

そして

Class B:
    @staticmethod
    def foo():  # no self parameter
        pass

これはpython2とpython3の間で変更されました:

python2:

>>> A.foo()
TypeError
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

python3:

>>> A.foo()
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

したがって@staticmethod、クラスから直接呼び出されるだけのforメソッドの使用 は、python3ではオプションになりました。クラスとインスタンスの両方から呼び出したい場合でも、@staticmethodデコレータを使用する必要があります。

他のケースはunutbus回答で十分カバーされています。


5

クラスメソッドは、インスタンスメソッドがインスタンスを受け取るのと同じように、クラスを暗黙の最初の引数として受け取ります。これは、クラスのオブジェクトではなく、クラスにバインドされているメソッドです。オブジェクトインスタンスではなく、クラスを指すクラスパラメータを取るため、クラスの状態にアクセスできます。クラスのすべてのインスタンスに適用されるクラスの状態を変更できます。たとえば、すべてのインスタンスに適用できるクラス変数を変更できます。

一方、静的メソッドは、クラスメソッドやインスタンスメソッドと比較して、暗黙の最初の引数を受け取りません。また、クラスの状態にアクセスしたり変更したりすることはできません。設計の観点からは正しい方法であるため、クラスにのみ属します。ただし、機能に関しては、実行時にクラスにバインドされません。

ガイドラインとして、ユーティリティとして静的メソッドを使用し、たとえばfactoryとしてクラスメソッドを使用します。または、シングルトンを定義することもできます。また、インスタンスメソッドを使用して、インスタンスの状態と動作をモデル化します。

私は明確だったと思います!


4

私の貢献は間違いを示し@classmethod@staticmethod、およびインスタンスは、間接的に呼び出すことができる方法など、インスタンスメソッド、@staticmethod。ただし@staticmethod、インスタンスから間接的にを呼び出すのではなく、インスタンスをプライベートにすることは、より「パイソン風」になる可能性があります。ここではプライベートメソッドから何かを取得する方法は示していませんが、基本的には同じ概念です。

#!python3

from os import system
system('cls')
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

class DemoClass(object):
    # instance methods need a class instance and
    # can access the instance through 'self'
    def instance_method_1(self):
        return 'called from inside the instance_method_1()'

    def instance_method_2(self):
        # an instance outside the class indirectly calls the static_method
        return self.static_method() + ' via instance_method_2()'

    # class methods don't need a class instance, they can't access the
    # instance (self) but they have access to the class itself via 'cls'
    @classmethod
    def class_method(cls):
        return 'called from inside the class_method()'

    # static methods don't have access to 'cls' or 'self', they work like
    # regular functions but belong to the class' namespace
    @staticmethod
    def static_method():
        return 'called from inside the static_method()'
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# works even if the class hasn't been instantiated
print(DemoClass.class_method() + '\n')
''' called from inside the class_method() '''

# works even if the class hasn't been instantiated
print(DemoClass.static_method() + '\n')
''' called from inside the static_method() '''
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# >>>>> all methods types can be called on a class instance <<<<<
# instantiate the class
democlassObj = DemoClass()

# call instance_method_1()
print(democlassObj.instance_method_1() + '\n')
''' called from inside the instance_method_1() '''

# # indirectly call static_method through instance_method_2(), there's really no use
# for this since a @staticmethod can be called whether the class has been
# instantiated or not
print(democlassObj.instance_method_2() + '\n')
''' called from inside the static_method() via instance_method_2() '''

# call class_method()
print(democlassObj.class_method() + '\n')
'''  called from inside the class_method() '''

# call static_method()
print(democlassObj.static_method())
''' called from inside the static_method() '''

"""
# whether the class is instantiated or not, this doesn't work
print(DemoClass.instance_method_1() + '\n')
'''
TypeError: TypeError: unbound method instancemethod() must be called with
DemoClass instance as first argument (got nothing instead)
'''
"""

2

名前が示すように、クラスメソッドは、オブジェクトではなくクラスに変更を加えるために使用されます。クラスを変更するには、クラスを更新する方法であるので、オブジェクト属性ではなくクラス属性を変更します。これが、クラスメソッドがクラス(従来は 'cls'で表される)を最初の引数として取る理由です。

class A(object):
    m=54

    @classmethod
    def class_method(cls):
        print "m is %d" % cls.m

一方、静的メソッドは、クラスにバインドされていない機能を実行するために使用されます。つまり、クラス変数を読み書きしません。したがって、静的メソッドはクラスを引数として取りません。これらは、クラスがクラスの目的に直接関連しない機能を実行できるようにするために使用されます。

class X(object):
    m=54 #will not be referenced

    @staticmethod
    def static_method():
        print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."

2

@staticmethodを文字通り分析するさまざまな洞察を提供する分析します。

クラスの通常のメソッドは、最初の引数としてインスタンスを取る暗黙の動的メソッドです。
対照的に、staticmethodはインスタンスを最初の引数として取らないため、「static」と呼ばれます

静的メソッドは確かに、クラス定義の外の関数と同じような通常の関数です。
ラッキーなことに、適用された場所に近づくためにクラスにグループ化されています。または、スクロールして見つけることができます。


2

の純粋なPythonバージョンを提供するstaticmethodclassmethod、言語レベルでの違いを理解するのに役立ちます。

どちらもデータ記述子ではありません(最初に記述子について理解していると、理解しやすくなります)。

class StaticMethod(object):
    "Emulate PyStaticMethod_Type() in Objects/funcobject.c"

    def __init__(self, f):
        self.f = f

    def __get__(self, obj, objtype=None):
        return self.f


class ClassMethod(object):
    "Emulate PyClassMethod_Type() in Objects/funcobject.c"
    def __init__(self, f):
        self.f = f

    def __get__(self, obj, cls=None):
        def inner(*args, **kwargs):
            if cls is None:
                cls = type(obj)
            return self.f(cls, *args, **kwargs)
        return inner

1

staticmethodは、継承階層内のオブジェクト、クラス、または親クラスの属性にはアクセスできません。クラスで直接(オブジェクトを作成せずに)呼び出すことができます。

classmethodはオブジェクトの属性にアクセスできません。ただし、継承階層内のクラスおよび親クラスの属性にはアクセスできます。クラスで直接(オブジェクトを作成せずに)呼び出すことができます。オブジェクトで呼び出された場合self.<attribute(s)>、アクセスせずにアクセスする通常のメソッドと同じですself.__class__.<attribute(s)>だけのです。

を含むクラスがあると考えてください。b=2オブジェクトを作成し、これをそのb=4中に再設定します。Staticmethodは以前のものから何にもアクセスできません。Classmethodはを.b==2介してのみアクセスできますcls.b。通常の方法では、.b==4via self.b.b==2viaの両方にアクセスできますself.__class__.b

KISSスタイルに従うことができます(シンプルで愚かさを保つ)self.attribute(s)。静的メソッドとクラスメソッドを使用しないでください。インスタンス化せずにクラスを使用せず、オブジェクトの属性のみにアクセスしてください。OOPがそのように実装されている言語がありますが、それは悪い考えではないと思います。:)


classmethodsのもう1つの重要なこと:クラスメソッドの属性を変更すると、この属性を明示的に設定していないこのクラスの既存のすべてのオブジェクトは、変更された値を持ちます。
mirek

-4

@staticmethodそれ以外の点ではiPythonの同じメソッドをすばやくハックアップすると、パフォーマンスが(ナノ秒単位で)わずかに向上することがわかりますが、それ以外の場合は機能しないようです。また、パフォーマンスの向上は、staticmethod()コンパイル中にメソッドを処理するという追加の作業(スクリプトを実行するときのコード実行の前に行われます)によっておそらくなくなるでしょう。

コードを読みやすくするため@staticmethodに、ナノ秒がカウントされる作業負荷にメソッドが使用されない限り、私は避けます。


7
「それ以外の場合は機能しないようです」:厳密には当てはまりません。上記の説明を参照してください。
キース・ピンソン、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.