次のように、クラスを初期化せずに呼び出すことができる Python の静的メソッドを使用することは可能ですか。
ClassName.static_method()
次のように、クラスを初期化せずに呼び出すことができる Python の静的メソッドを使用することは可能ですか。
ClassName.static_method()
はい、 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 で変更: 関数デコレータ構文が追加されました。
私はスティーブンが実際に正しいと思います。元の質問に答えるには、クラス メソッドを設定するために、最初の引数が呼び出し元のインスタンスにならないと仮定し、クラスからのみメソッドを呼び出すようにします。
(この回答は 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)
はい、staticmethodデコレーターをチェックしてください。
>>> class C:
... @staticmethod
... def hello():
... print "Hello World"
...
>>> C.hello()
Hello World
@staticmethod
デコレータを実際に使用する必要はありません。メソッド(selfパラメーターを予期しない)を宣言し、クラスから呼び出すだけです。デコレータは、インスタンスからも呼び出すことができるようにしたい場合にのみ存在します(これはあなたが望んでいたことではありませんでした)
ほとんどの場合、関数を使用するだけですが...
静的メソッド オブジェクトがどのように動作するかという特殊性は別として、モジュール レベルのコードを整理する際に、静的メソッド オブジェクトを使用すると、特定の種類の美点を見つけることができます。
# 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
他の人の回答を要約して追加すると、 pythonで静的メソッドまたは変数を宣言する方法はたくさんあります。
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
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
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
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
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 ドキュメントを参照してください。