web-dev-qa-db-ja.com

Pythonの静的メソッド?

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

ClassName.StaticMethod ( )
1549
Joan Venge

うん、 staticメソッド デコレータを使う

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を使用)とまったく同じですが、Niceデコレータ構文を使用していません。

最後に、 staticmethod() を控えめに使用してください。 Pythonで静的メソッドが必要な状況はごくわずかですが、私はそれらが別々の「トップレベル」関数がより明確になるであろう場所で何度も使用されるのを見ました。


以下はドキュメントから逐語的です:

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

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

@staticmethod形式は関数です。 デコレータ - 詳細は 関数定義 の関数定義の説明を参照してください。

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

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

静的メソッドの詳細については、 標準型階層 にある標準型階層に関するドキュメントを参照してください。

バージョン2.2の新機能.

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

1862
dbr

Stevenは実際に正しいと思います 。元の質問に答えるには、クラスメソッドを設定するために、最初の引数が呼び出し元のインスタンスにならないと仮定して、クラスからメソッドを呼び出すだけであることを確認します。

(この答えは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)

ただし、自身と-1の2つの引数を送信するため、例外が発生します。 "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)
195
Richard Ambler

はい、 staticmethod デコレータをチェックしてください。

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World
77

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

ほとんどの場合、あなたはただ関数を使用します...

46
Steven

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()

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


あなたが説明するのに使うことができるもう一つのオプションはclassmethodです、違いは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'])
32
Aaron Hall

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

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.Dog.barking_soundではなくdogs.barking_sound()を呼び出します。

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

9
Matt Woelk

静的メソッドオブジェクト の振る舞いの特殊性は別として、モジュールレベルのコードをまとめることに関しては、ある種の美しさがあります。

# 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個のモジュールで120個のLOCを持ち、残りはせいぜい2ダースの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
9

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

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

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

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

0
Aman Raheja