Pythonの静的メソッド?


1719

次のように、クラスを初期化せずに呼び出すことができる静的メソッドをPythonに含めることは可能ですか?

ClassName.static_method()

回答:


2026

はい、staticmethodデコレータを使用します

class MyClass(object):
    @staticmethod
    def the_static_method(x):
        print(x)

MyClass.the_static_method(2)  # outputs 2

一部のコードは、静的メソッドを定義する古いメソッドを使用staticmethodして、デコレータではなく関数として使用する場合があることに注意してください。これは、Pythonの古いバージョン(2.2および2.3)をサポートする必要がある場合にのみ使用してください。

class MyClass(object):
    def the_static_method(x):
        print(x)
    the_static_method = staticmethod(the_static_method)

MyClass.the_static_method(2)  # outputs 2

これは最初の例とまったく同じです(を使用@staticmethod)。

最後に、staticmethod()控えめに使用してください!Pythonで静的メソッドが必要となる状況は非常に少なく、個別の「トップレベル」関数がより明確である場合に、それらが何度も使用されるのを見てきました。


以下は、ドキュメントからそのままです

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

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

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

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

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

静的メソッドの詳細については、内標準型の階層上の文書相談の標準型の階層を

バージョン2.2の新機能。

バージョン2.4で変更:関数デコレータ構文が追加されました。


15
@staticmethod最初のselfパラメーターを単に回避できるのに、なぜ装飾を追加するか、関数ポインターを使用するのですか?まあ、オブジェクトの場合aa.your_static_method()他の言語では許可されているを呼び出すことはできませんが、とにかくそれは悪い習慣と見なされ、コンパイラは常にそれについて警告します
SomethingSomething

1
私はPython 2.7.12を使用していますが、@ staticmethodデコレータを使用して、定義されている最初の静的メソッドを呼び出すことができません。そのエラー:TypeError: 'staticmethod'オブジェクトは呼び出し可能ではありません
Supratim Samantray 2017

Supratim Samantray、よろしいですか?ので、ここでは明確にそれが2.4後に使用することができると述べています。
realslimshanky 2018年

11
@SomethingSomething、変数名「self」を使用せず、デコレータを追加しない場合、最初の引数(例:arg1)は引き続きselfインスタンスへの参照になります。セルフという名前は慣例にすぎません。
George Moutsopoulos

1
@GeorgeMoutsopoulos-概ね合意。ただしClassName.methodName()、静的メソッドであるかのように、メソッドをとして呼び出すことができ、メソッドには何selfも提供されません。あなたが言ったように、まだとしても、このメソッドを呼び出すことが可能になりClassInstance.methodName()、そしてself関係なく、その名前の、最初のパラメータとして提供されます。
SomethingSomething

220

私はスティーブンが実際に正しいと思います。元の質問に答えるには、クラスメソッドを設定するために、最初の引数が呼び出し元のインスタンスではないと想定し、クラスからのみメソッドを呼び出すようにします。

(この回答はPython 3.xを指していることに注意してください。Python2.xではTypeError、クラス自体のメソッドを呼び出すためのを取得します。)

例えば:

class Dog:
    count = 0 # this is a class variable
    dogs = [] # this is a class variable

    def __init__(self, name):
        self.name = name #self.name is an instance variable
        Dog.count += 1
        Dog.dogs.append(name)

    def bark(self, n): # this is an instance method
        print("{} says: {}".format(self.name, "woof! " * n))

    def rollCall(n): #this is implicitly a class method (see comments below)
        print("There are {} dogs.".format(Dog.count))
        if n >= len(Dog.dogs) or n < 0:
            print("They are:")
            for dog in Dog.dogs:
                print("  {}".format(dog))
        else:
            print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))

fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)

このコードでは、「rollCall」メソッドは最初の引数がインスタンスではないことを前提としています(クラスではなくインスタンスによって呼び出された場合と同様)。「rollCall」がインスタンスではなくクラスから呼び出される限り、コードは正常に動作します。インスタンスから "rollCall"を呼び出そうとすると、例えば:

rex.rollCall(-1)

ただし、2つの引数(それ自体と-1)を送信するため、例外が発生し、「rollCall」は1つの引数を受け入れるようにのみ定義されています。

ちなみに、rex.rollCall()は正しい数の引数を送信しますが、関数がnが数値であることを期待している場合、nはDogインスタンス(つまりrex)を表すため、例外も発生します。

これが装飾の出番です。「rollCall」メソッドの前に

@staticmethod

次に、メソッドが静的であることを明示的に示すことで、インスタンスから呼び出すこともできます。さて、

rex.rollCall(-1)

うまくいくでしょう。メソッド定義の前に@staticmethodを挿入すると、インスタンスはそれ自体を引数として送信しなくなります。

@staticmethod行をコメント化して、またはコメント化せずに次のコードを試して、これを確認できます。

class Dog:
    count = 0 # this is a class variable
    dogs = [] # this is a class variable

    def __init__(self, name):
        self.name = name #self.name is an instance variable
        Dog.count += 1
        Dog.dogs.append(name)

    def bark(self, n): # this is an instance method
        print("{} says: {}".format(self.name, "woof! " * n))

    @staticmethod
    def rollCall(n):
        print("There are {} dogs.".format(Dog.count))
        if n >= len(Dog.dogs) or n < 0:
            print("They are:")
            for dog in Dog.dogs:
                print("  {}".format(dog))
        else:
            print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))


fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
rex.rollCall(-1)

8
最初の例(@staticmethodなしのクラスによる呼び出し)は、Python 2.7では機能しません。「TypeError:バインドされていないメソッドrollCall()を最初の引数としてDogインスタンスで呼び出す必要があります(代わりにintインスタンスを取得)」
tba

2
これは動作しません。Dog.rollCall(-1)とrex.rollCall(-1)の両方が同じ値を返すTypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead)
Mittenchops 2013年

3
@MestreLion静的メソッドとインスタンスメソッドを組み合わせて、一方を他方のように見せることだけができるので、これは大きなメリットではないと思います。メソッドが静的であることがわかっている場合は、静的メソッドとしてアクセスする必要があります。メソッドがインスタンスを必要としない、または使用しないという事実は、メソッドを使用する場所に関係なく自明です。これはより明確で、静的メソッドを呼び出していることがすぐにわかるので、常にT.my_static_method()or を使用しますtype(my_t_instance).my_static_method()
Asad Saeeduddin 2014年


54

あなたは本当に使用する必要はありません @staticmethodデコレータ。メソッド(selfパラメータを必要としないもの)を宣言し、クラスから呼び出すだけです。デコレータは、インスタンスからも呼び出すことができるようにする場合にのみ存在します(これは望んでいたことではありませんでした)。

ほとんどの場合、関数を使用しますが...


これはpython 2.5.2では機能しません。 class Dummy: def static1(): print "hello from static1" @staticmethod def static2(): print "hello from static2" Dummy.static2() Dummy.static1() 出力:hello from static2 Traceback <most last call last>:File "ll.py"、line 46、in <module> Dummy.static1()TypeError:unbound method static1()must be最初の引数としてダミーインスタンスを使用して呼び出された(代わりに何も入力されなかった)
Mahori 2012

7
これはクラス内では機能しません。Pythonはself、指定しない限り、最初の引数として渡します。(参照:デコレータ)
Navin、2013

9
実際、これは2.7では間違っており、3.Xの時点では合法です(3.2でテスト済み)。つまり、2.7以下では@staticmethodデコレータなしではクラスのコンテキストからメソッドを呼び出すことができません。3.2では機能しself、呼び出し方法に応じて適切にref を挿入します。テストケース:pastebin.com/12DDV7DB
spinkus 2014

2
技術的には正確ですが、ひどい解決策です。staticmethodデコレータは、1つのクラスとインスタンス(インスタンス上の関数を呼び出すときに、この解決策が失敗した)の両方で機能を呼び出すことができます。
イーサンファーマン2017

メソッドは、ドット表記を使用して、オブジェクトの他の属性と同様に呼び出すことができます。class C: def callme(): print('called'); C.callme()
pouya

32

Pythonの静的メソッド?

Pythonに静的メソッドを含めることができるので、クラスを初期化せずにそれらを呼び出すことができます。

ClassName.StaticMethod()

はい、静的メソッドは次のように作成できます(メソッドにCamelCaseではなくアンダースコアを使用する方が少しPythonicですが)。

class ClassName(object):

    @staticmethod
    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

上記はデコレータ構文を使用しています。この構文は次と同等です。

class ClassName(object):

    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

    static_method = staticmethod(static_method)

これは、説明したとおりに使用できます。

ClassName.static_method()

静的メソッドの組み込み例はstr.maketrans()Python 3にあり、これはstringPython 2のモジュールの関数でした。


説明するように使用できる別のオプションclassmethodはです。違いは、クラスメソッドがクラスを暗黙の最初の引数として取得し、サブクラス化されている場合、サブクラスを暗黙の最初の引数として取得することです。

class ClassName(object):

    @classmethod
    def class_method(cls, kwarg1=None):
        '''return a value that is a function of the class and kwarg1'''

clsは最初の引数に必須の名前ではないことに注意してください。ただし、経験豊富なPythonコーディング担当者のほとんどは、他の引数を使用した場合、それが不適切であると見なします。

これらは通常、代替コンストラクタとして使用されます。

new_instance = ClassName.class_method()

組み込みの例はdict.fromkeys()次のとおりです。

new_dict = dict.fromkeys(['key1', 'key2'])

11

静的メソッドオブジェクトの動作の特殊性は別として、モジュールレベルのコードの編成に関しては、それらに打ち勝つことができるある種の美しさがあります。

# garden.py
def trim(a):
    pass

def strip(a):
    pass

def bunch(a, b):
    pass

def _foo(foo):
    pass

class powertools(object):
    """
    Provides much regarded gardening power tools.
    """
    @staticmethod
    def answer_to_the_ultimate_question_of_life_the_universe_and_everything():
        return 42

    @staticmethod
    def random():
        return 13

    @staticmethod
    def promise():
        return True

def _bar(baz, quux):
    pass

class _Dice(object):
    pass

class _6d(_Dice):
    pass

class _12d(_Dice):
    pass

class _Smarter:
    pass

class _MagicalPonies:
    pass

class _Samurai:
    pass

class Foo(_6d, _Samurai):
    pass

class Bar(_12d, _Smarter, _MagicalPonies):
    pass

...

# tests.py
import unittest
import garden

class GardenTests(unittest.TestCase):
    pass

class PowertoolsTests(unittest.TestCase):
    pass

class FooTests(unittest.TestCase):
    pass

class BarTests(unittest.TestCase):
    pass

...

# interactive.py
from garden import trim, bunch, Foo

f = trim(Foo())
bunch(f, Foo())

...

# my_garden.py
import garden
from garden import powertools

class _Cowboy(garden._Samurai):
    def hit():
        return powertools.promise() and powertools.random() or 0

class Foo(_Cowboy, garden.Foo):
    pass

特定のコンポーネントを使用することを意図したコンテキストで、もう少し直感的で自己文書化され、明確なテストケースの命名や、テストモジュールが純粋なテスト用の実際のモジュールにどのようにマッピングされるかをわかりやすくするためのアプローチが理想的です。 。

このアプローチをプロジェクトのユーティリティコードの整理に適用することが現実的であることがよくあります。多くの場合、人々はすぐに急いでutilsパッケージを作成し、最終的に9つのモジュールで終わります。そのうちの1つは120 LOCで、残りは最高で20のLOCです。私はこれから始めて、それをパッケージに変換し、本当にそれらにふさわしい獣のためだけにモジュールを作成することを好みます:

# utils.py
class socket(object):
    @staticmethod
    def check_if_port_available(port):
        pass

    @staticmethod
    def get_free_port(port)
        pass

class image(object):
    @staticmethod
    def to_rgb(image):
        pass

    @staticmethod
    def to_cmyk(image):
        pass

10

おそらく最も簡単なオプションは、これらの関数をクラスの外に置くことです:

class Dog(object):
    def __init__(self, name):
        self.name = name

    def bark(self):
        if self.name == "Doggy":
            return barking_sound()
        else:
            return "yip yip"

def barking_sound():
    return "woof woof"

このメソッドを使用すると、内部オブジェクトの状態を変更または使用する(副作用がある)関数をクラスに保持でき、再利用可能なユーティリティ関数を外部に移動できます。

このファイルがと呼ばれているとしましょうdogs.py。これらを使用するには、dogs.barking_sound()ではなくを呼び出しますdogs.Dog.barking_sound

あなたが本当にクラスの一部であることを静的メソッドが必要な場合は、使用することができstaticmethodのデコレータを。


1

したがって、静的メソッドは、クラスのオブジェクトを作成せずに呼び出すことができるメソッドです。例えば ​​:-

    @staticmethod
    def add(a, b):
        return a + b

b = A.add(12,12)
print b

上記の例では、メソッドaddAオブジェクト名ではなくクラス名によって呼び出されます。


-3

Python Staticメソッドは2つの方法で作成できます。

  1. staticmethod()の使用

    class Arithmetic:
        def add(x, y):
            return x + y
    # create add static method
    Arithmetic.add = staticmethod(Arithmetic.add)
    
    print('Result:', Arithmetic.add(15, 10))

出力:

結果:25

  1. @staticmethodの使用

    class Arithmetic:
    
    # create add static method
    @staticmethod
    def add(x, y):
        return x + y
    
    print('Result:', Arithmetic.add(15, 10))

出力:

結果:25


あなたは例を提供し、それを行う方法の方法を共有しました。メソッドの意味を説明しませんでした。
zixuan

-4

私は時々この質問に遭遇します。私が気に入っているユースケースと例は次のとおりです。

jeffs@jeffs-desktop:/home/jeffs  $ python36
Python 3.6.1 (default, Sep  7 2017, 16:36:03) 
[GCC 6.3.0 20170406] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cmath
>>> print(cmath.sqrt(-4))
2j
>>>
>>> dir(cmath)
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cos', 'cosh', 'e', 'exp', 'inf', 'infj', 'isclose', 'isfinite', 'isinf', 'isnan', 'log', 'log10', 'nan', 'nanj', 'phase', 'pi', 'polar', 'rect', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau']
>>> 

cmathオブジェクトには状態がないため、クラスcmathのオブジェクトを作成しても意味がありません。ただし、cmathは何らかの方法で関連しているメソッドのコレクションです。上記の私の例では、cmathのすべての関数が何らかの方法で複素数に作用します。


あなたは質問に答えませんでしたが、代わりに例を提供しました。
zixuan
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.