1894

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

ClassName.static_method()
4

11 に答える 11

2173

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

最後に、staticmethod控えめに使用してください!Python で static-methods が必要になる状況はほとんどありません。別の「トップレベル」関数の方が明確な場合に、static-methods が何度も使用されているのを見てきました。


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

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

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

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

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

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

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

バージョン 2.2 の新機能。

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

于 2009-04-09T21:24:36.013 に答える
241

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

(この回答は Python 3.x を参照していることに注意してください。Python 2.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)
于 2012-04-18T09:16:03.530 に答える
89

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

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World
于 2009-04-09T21:24:15.047 に答える
61

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

ほとんどの場合、関数を使用するだけですが...

于 2009-04-10T16:00:50.773 に答える
13

静的メソッド オブジェクトがどのように動作するかという特殊性は別として、モジュール レベルのコードを整理する際に、静的メソッド オブジェクトを使用すると、特定の種類の美点を見つけることができます。

# 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パッケージを作成し、そのうちの 1 つが 120 LOC で、残りがせいぜい 20 個の LOC である 9 つのモジュールになってしまいます。私はこれから始めて、それをパッケージに変換し、本当にそれに値する獣のためだけにモジュールを作成することを好みます:

# 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
于 2012-12-29T19:47:13.523 に答える
2

他の人の回答を要約して追加すると、 pythonで静的メソッドまたは変数を宣言する方法はたくさんあります。

  1. staticmethod()をデコレーターとして使用する: 宣言されたメソッド (関数) の上にデコレーターを置くだけで、静的メソッドにすることができます。たとえば。
class Calculator:
    @staticmethod
    def multiply(n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 * n2 * Res

print(Calculator.multiply(1, 2, 3, 4))              # 24
  1. パラメータ関数としてstaticmethod()を使用する: このメソッドは、関数型の引数を受け取ることができ、渡された関数の静的バージョンを返します。たとえば。
class Calculator:
    def add(n1, n2, *args):
        return n1 + n2 + sum(args)

Calculator.add = staticmethod(Calculator.add)
print(Calculator.add(1, 2, 3, 4))                   # 10
  1. classmethod()をデコレーターとして使用する: @classmethod は @staticmethod と同様の効果を関数に与えますが、今回は追加の引数を関数で受け入れる必要があります (インスタンス変数の self パラメーターに似ています)。たとえば。
class Calculator:
    num = 0
    def __init__(self, digits) -> None:
        Calculator.num = int(''.join(digits))

    @classmethod
    def get_digits(cls, num):
        digits = list(str(num))
        calc = cls(digits)
        return calc.num

print(Calculator.get_digits(314159))                # 314159
  1. classmethod()をパラメーター関数として使用する: クラス定義を変更したくない場合は、@classmethod をパラメーター関数として使用することもできます。たとえば。
class Calculator:
    def divide(cls, n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 / n2 / Res

Calculator.divide = classmethod(Calculator.divide)

print(Calculator.divide(15, 3, 5))                  # 1.0
  1. 直接宣言 他のすべてのメソッドの外側で宣言されているが、クラスの内側で宣言されているメソッド/変数は、自動的に静的になります。
class Calculator:   
    def subtract(n1, n2, *args):
        return n1 - n2 - sum(args)

print(Calculator.subtract(10, 2, 3, 4))             # 1

プログラム全体

class Calculator:
    num = 0
    def __init__(self, digits) -> None:
        Calculator.num = int(''.join(digits))
    
    
    @staticmethod
    def multiply(n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 * n2 * Res


    def add(n1, n2, *args):
        return n1 + n2 + sum(args)
    

    @classmethod
    def get_digits(cls, num):
        digits = list(str(num))
        calc = cls(digits)
        return calc.num


    def divide(cls, n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 / n2 / Res


    def subtract(n1, n2, *args):
        return n1 - n2 - sum(args)
    



Calculator.add = staticmethod(Calculator.add)
Calculator.divide = classmethod(Calculator.divide)

print(Calculator.multiply(1, 2, 3, 4))              # 24
print(Calculator.add(1, 2, 3, 4))                   # 10
print(Calculator.get_digits(314159))                # 314159
print(Calculator.divide(15, 3, 5))                  # 1.0
print(Calculator.subtract(10, 2, 3, 4))             # 1

Pythonで OOP を習得するには、 Python ドキュメントを参照してください。

于 2021-10-26T17:11:02.747 に答える