呼び出し - python3 class method static method




@staticmethodと@classmethodの違いは何ですか? (16)

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

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

', '

インスタンスメソッドを使用して、この文字列を結合して別のiterableに結合すると、iterableリストの関数であることに加えて、インスタンスの関数であることは明らかです。 ['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'

静的メソッド

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

モジュールレベルの機能に非常によく似ています。

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

ただし、オブジェクトにアタッチされている場合は、インポートおよび継承によってオブジェクトに便利に従います。

静的メソッドの例は、 str.maketransです。これは、Python 3のstringモジュールから移動されますstr.translateによる消費に適した変換テーブルをstr.translateます。 以下に示すように、文字列のインスタンスから使用すると、むしろばかげているように見えますが、文字stringモジュールから関数をインポートするのはむしろstr.maketransように、クラスから呼び出すことができ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'>

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

https://code.i-harness.com

@staticmethodで装飾された関数と@staticmethodで装飾された関数の違いは何ですか?


@classmethodと@staticmethodの間の類似性を最初に教えてください。

類似点:どちらもクラスインスタンスではなく、 クラス自体で呼び出すことができます。 ですから、どちらの意味でもClassのメソッドです。

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

したがって、静的メソッドは、ある意味では、クラス自体にバインドされておらず、単に関連する機能を持つ可能性があるからです。

>>> 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',)

@ececatorsが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)

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

_is_cluster_forメソッドをクラスメソッドにするもう1つのメリットは、サブクラスが実装の変更を決めることができるようにすることです。これはかなり汎用的で複数のタイプのクラスターを処理できるためです。


Hereでこの質問の短い記事です

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

@classmethod関数もクラスをインスタンス化せずに呼び出し可能ですが、その定義は継承を介してParentクラスではなくSubクラスに従います。 @classmethod関数の最初の引数は常にcls(クラス)でなければならないからです。


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

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

  • Pythonはオブジェクトのバウンドメソッドをインスタンス化する必要はありません。
  • コードの可読性が容易になり、オブジェクト自体の状態に依存しません。

@classmethod関数もクラスをインスタンス化せずに呼び出し可能ですが、その定義は継承を介してParentクラスではなくSubクラスに従い、サブクラスでオーバーライドできます。 @classmethod関数の最初の引数は常にcls (クラス)でなければならないからです。

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

@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'>

クラスメソッドとPythonの静的メソッド

クラスメソッド

@classmethodデコレータは、関数が定義された後に評価される式である組み込み関数デコレータです。 その評価の結果は、あなたの関数定義を陰にします。

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

構文:

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

fun: function that needs to be converted into a class method
returns: a class method for function.
  • クラスメソッドはクラスにバインドされたメソッドであり、クラスのオブジェクトではありません。
  • オブジェクトインスタンスではなくクラスを指すクラスパラメータを取るので、クラスの状態にアクセスできます。
  • クラスのすべてのインスタンスに適用されるクラス状態を変更できます。 たとえば、すべてのインスタンスに適用可能なクラス変数を変更できます。

静的メソッド

静的メソッドは暗黙の第1引数を受け取りません。

構文:

class C(object):
    @staticmethod
    def fun(arg1, arg2, ...):
        ...
returns: a static method for function fun.
  • 静的メソッドは、クラスにバインドされたメソッドでもあり、クラスのオブジェクトではありません。
  • 静的メソッドはクラスの状態にアクセスしたり、クラスの状態を変更することはできません。
  • メソッドがクラス内に存在することは意味があるので、クラス内に存在します。

クラスメソッドと静的メソッド

  • クラスメソッドは第1パラメータとしてclsをとりますが、静的メソッドは特定のパラメータを必要としません。
  • クラスメソッドは、静的メソッドがアクセスまたは変更できない間に、クラス状態にアクセスまたは変更できます。
  • Pythonでは@classmethodデコレータを使用してクラスメソッドを作成し、@staticmethodデコレータを使用してPythonでスタティックメソッドを作成します。

何を使うの?

  • 私たちは、通常、ファクトリメソッドを作成するためにクラスメソッドを使用します。 ファクトリメソッドは、さまざまなユースケースに対してクラスオブジェクト(コンストラクタに似ています)を返します。
  • 私たちは一般に、静的メソッドを使用してユーティリティ関数を作成します。

どのようにクラスメソッドと静的メソッドを定義するのですか?

Pythonでクラスメソッドを定義するには、@classmethodデコレータを使用し、@staticmethodデコレータを使用する静的メソッドを定義します。

両方の違いを理解するための例を見てみましょう。 Personというクラスを作成したいとしましょう。 現在、PythonはC ++やJavaのようなメソッドのオーバーロードをサポートしていないので、クラスメソッドを使用してファクトリメソッドを作成しています。 以下の例では、classメソッドを使用して、誕生年からpersonオブジェクトを作成します。

上で説明したように、私たちは静的メソッドを使用してユーティリティ関数を作成します。 以下の例では、人が大人であるかどうかを確認するために静的メソッドを使用しています。

実装

# Python program to demonstrate 
# use of class method and static method.
from datetime import date

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # a class method to create a Person object by birth year.
    @classmethod
    def fromBirthYear(cls, name, year):
        return cls(name, date.today().year - year)

    # a static method to check if a Person is adult or not.
    @staticmethod
    def isAdult(age):
        return age > 18

person1 = Person('mayank', 21)
person2 = Person.fromBirthYear('mayank', 1996)

print person1.age
print person2.age

# print the result
print Person.isAdult(22)

出力

21
21
True

Reference


公式のpythonドキュメント:

@classmethod

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

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

@classmethodフォームは関数decoratorです。詳細は、 関数定義の関数定義の説明を参照してください。

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

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

@staticmethod

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

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

@staticmethodフォームは関数decoratorです。詳細は、 関数定義の関数定義の説明を参照してください。

これは、クラス( Cf() )またはインスタンス( C().f()など)で呼び出すことができます。 インスタンスはそのクラスを除いて無視されます。

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


たぶん少しのコード例が役に立ちます: fooclass_foostatic_foo呼び出しシグネチャの違いにclass_fooしてstatic_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つの使用法は、 継承可能な代替コンストラクタを作成することです。

staticメソッドでは、 self (オブジェクトインスタンス)もcls (クラス)も暗黙的に第1引数として渡されません。 インスタンスやクラスから呼び出すことができる点を除いて、プレーン関数のように動作します。

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

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

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

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

afooバインドされています。 これは、以下の用語「束縛」によって意味されるものである:

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

a.class_fooでは、 aa.class_fooにバインドされず、class Aclass_fooバインドされclass_foo

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

ここで、 a.static_fooメソッドでは、たとえそれがメソッドであっても、 a.static_fooは引数がバインドされていない良い 'ole関数を返します。 static_fooは1つの引数をa.static_fooa.static_fooは1つの引数も必要とします。

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

もちろん、クラスA static_fooを呼び出すと、同じことが起こります。

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

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


私はC ++、Java、そしてPythonでプログラミング言語を学び始めました。そして、この質問は、私がそれぞれの簡単な使い方を理解するまで、私にも邪魔になりました。

クラスメソッド: PythonはJavaと異なり、C ++にはコンストラクタのオーバーロードがありません。 そして、これを達成するために、 classmethod使用することができます。 以下の例でこれについて説明します

first_namelast_nameという2つの引数をとり、 Personのインスタンスを作成する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

クラス名を使って簡単に呼び出すことができます

Person.validate_name("Gaurang Shah")

私はより良い質問は "@classmethodと@staticmethodのどちらを使うのですか?"ということです。

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

@staticmethodはパフォーマンス上の限界がありますが、クラス外のスタンドアロン関数としては達成できなかった、クラス内の静的メソッドの生産的使用をまだ見ていません。


静的メソッド対クラスメソッドに関するもう一つの考慮事項は、継承を伴います。 次のクラスがあるとします。

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

そして、子クラスのbar()をオーバーライドする必要があります:

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

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

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" 

この問題を回避するには、 bar() Foo2.magic()内のFoo2.magic()を呼び出すことですが、あなた自身が繰り返しています( 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


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

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

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


クラスメソッドは、名前が示唆するように、オブジェクトではなくクラスを変更するために使用されます。クラスを変更するには、クラス属性を変更します(オブジェクト属性ではない)。これはクラスの更新方法です。これは、クラスメソッドがクラス(通常は '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."

#!/usr/bin/python
#coding:utf-8

class Demo(object):
    def __init__(self,x):
        self.x = x

    @classmethod
    def addone(self, x):
        return x+1

    @staticmethod
    def addtwo(x):
        return x+2

    def addthree(self, x):
        return x+3

def main():
    print Demo.addone(2)
    print Demo.addtwo(2)

    #print Demo.addthree(2) #Error
    demo = Demo(2)
    print demo.addthree(2)


if __name__ == '__main__':
    main()




python-decorators