@staticmethod
で装飾された関数とで装飾された関数の違いは何@classmethod
ですか?
33 に答える
たぶん、コード例が少し役に立ちます: と の呼び出しシグネチャの違いに注意してfoo
ください:class_foo
static_foo
class A(object):
def foo(self, x):
print(f"executing foo({self}, {x})")
@classmethod
def class_foo(cls, x):
print(f"executing class_foo({cls}, {x})")
@staticmethod
def static_foo(x):
print(f"executing static_foo({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 つは、継承可能な代替コンストラクターを作成することです。
staticmethodsでは、self
(オブジェクト インスタンス) も cls
(クラス) も最初の引数として暗黙的に渡されません。これらは、インスタンスまたはクラスから呼び出すことができることを除いて、単純な関数のように動作します。
a.static_foo(1)
# executing static_foo(1)
A.static_foo('hi')
# executing static_foo(hi)
staticmethods は、クラスへのクラスとの論理的な接続を持つ関数をグループ化するために使用されます。
foo
は単なる関数ですが、呼び出すとa.foo
、関数を取得するだけでなく、関数a
の最初の引数としてオブジェクト インスタンスがバインドされた関数の「部分的に適用された」バージョンが取得されます。foo
は 2 つの引数を想定していますが、引数a.foo
は 1 つしか想定していません。
a
にバインドされていfoo
ます。これが、以下の「バインド」という用語の意味です。
print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>
がにバインドされているのa.class_foo
ではなく、クラスが にバインドされています。a
class_foo
A
class_foo
print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>
ここで、 staticmethod を使用すると、メソッドであるにもかかわらず、a.static_foo
引数がバインドされていない適切な 'ole 関数が返されます。static_foo
1 つの引数が必要であり、
a.static_foo
1 つの引数も必要です。
print(a.static_foo)
# <function static_foo at 0xb7d479cc>
もちろん、代わりstatic_foo
にクラスを呼び出した場合も同じことが起こります。A
print(A.static_foo)
# <function static_foo at 0xb7d479cc>
staticmethodは、呼び出されたクラスまたはインスタンスについて何も知らないメソッドです。暗黙的な最初の引数ではなく、渡された引数を取得するだけです。これは基本的に Python では役に立ちません。静的メソッドの代わりにモジュール関数を使用できます。
一方、classmethodは、呼び出されたクラス、または呼び出されたインスタンスのクラスを最初の引数として渡すメソッドです。これは、メソッドをクラスのファクトリにしたい場合に便利です。最初の引数として呼び出された実際のクラスを取得するため、サブクラスが含まれている場合でも、常に適切なクラスをインスタンス化できます。dict.fromkeys()
たとえば、サブクラスで呼び出されたときにクラスメソッドである がサブクラスのインスタンスを返す方法を観察します。
>>> class DictSubclass(dict):
... def __repr__(self):
... return "DictSubclass"
...
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>>
基本的@classmethod
に、最初の引数が(クラスインスタンスではなく)呼び出されたクラスであるメソッドを作成し、@staticmethod
暗黙の引数を持ちません。
公式の python ドキュメント:
クラス メソッドは、インスタンス メソッドがインスタンスを受け取るのと同様に、暗黙的な最初の引数としてクラスを受け取ります。クラス メソッドを宣言するには、次のイディオムを使用します。
class C: @classmethod def f(cls, arg1, arg2, ...): ...
@classmethod
フォームは関数 デコレーターです。詳細については、関数定義の関数定義の説明を参照してください。クラス ( など
C.f()
) またはインスタンス ( など)で呼び出すことができますC().f()
。インスタンスは、そのクラスを除いて無視されます。派生クラスに対してクラス メソッドが呼び出される場合、派生クラス オブジェクトは暗黙の最初の引数として渡されます。クラス メソッドは、C++ または Java の静的メソッドとは異なります。それらが必要な場合は
staticmethod()
、このセクションを参照してください。
静的メソッドは、暗黙的な最初の引数を受け取りません。静的メソッドを宣言するには、次のイディオムを使用します。
class C: @staticmethod def f(arg1, arg2, ...): ...
@staticmethod
フォームは関数 デコレーターです。詳細については、関数定義の関数定義の説明を参照してください。クラス ( など
C.f()
) またはインスタンス ( など)で呼び出すことができますC().f()
。インスタンスは、そのクラスを除いて無視されます。Python の静的メソッドは、Java や C++ の静的メソッドに似ています。より高度な概念については
classmethod()
、このセクションの を参照してください。
@staticmethodと@classmethod のどちらを使用するかを決定するには、メソッド内を調べる必要があります。メソッドがクラス内の他の変数/メソッドにアクセスする場合は、 @classmethod を使用します。一方、メソッドがクラスの他の部分に触れない場合は、@staticmethod を使用します。
class Apple:
_counter = 0
@staticmethod
def about_apple():
print('Apple is good for you.')
# note you can still access other member of the class
# but you have to use the class instance
# which is not very nice, because you have repeat yourself
#
# For example:
# @staticmethod
# print('Number of apples have been juiced: %s' % Apple._counter)
#
# @classmethod
# print('Number of apples have been juiced: %s' % cls._counter)
#
# @classmethod is especially useful when you move your function to another class,
# you don't have to rename the referenced class
@classmethod
def make_apple_juice(cls, number_of_apples):
print('Making juice:')
for i in range(number_of_apples):
cls._juice_this(i)
@classmethod
def _juice_this(cls, apple):
print('Juicing apple %d...' % apple)
cls._counter += 1
これは、この質問に関する短い記事です
@staticmethod 関数は、クラス内で定義された関数にすぎません。最初にクラスをインスタンス化せずに呼び出すことができます。その定義は継承によって不変です。
@classmethod 関数は、クラスをインスタンス化せずに呼び出すこともできますが、その定義は、親クラスではなく、継承を介してサブクラスに従います。これは、@classmethod 関数の最初の引数が常に cls (クラス) でなければならないためです。
What is the difference between @staticmethod and @classmethod in Python?
You may have seen Python code like this pseudocode, which demonstrates the signatures of the various method types and provides a docstring to explain each:
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.
'''
The Normal Instance Method
First I'll explain a_normal_instance_method
. This is precisely called an "instance method". When an instance method is used, it is used as a partial function (as opposed to a total function, defined for all values when viewed in source code) that is, when used, the first of the arguments is predefined as the instance of the object, with all of its given attributes. It has the instance of the object bound to it, and it must be called from an instance of the object. Typically, it will access various attributes of the instance.
For example, this is an instance of a string:
', '
if we use the instance method, join
on this string, to join another iterable,
it quite obviously is a function of the instance, in addition to being a function of the iterable list, ['a', 'b', 'c']
:
>>> ', '.join(['a', 'b', 'c'])
'a, b, c'
Bound methods
Instance methods can be bound via a dotted lookup for use later.
For example, this binds the str.join
method to the ':'
instance:
>>> join_with_colons = ':'.join
And later we can use this as a function that already has the first argument bound to it. In this way, it works like a partial function on the instance:
>>> join_with_colons('abcde')
'a:b:c:d:e'
>>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF'])
'FF:FF:FF:FF:FF:FF'
Static Method
The static method does not take the instance as an argument.
It is very similar to a module level function.
However, a module level function must live in the module and be specially imported to other places where it is used.
If it is attached to the object, however, it will follow the object conveniently through importing and inheritance as well.
An example of a static method is str.maketrans
, moved from the string
module in Python 3. It makes a translation table suitable for consumption by str.translate
. It does seem rather silly when used from an instance of a string, as demonstrated below, but importing the function from the string
module is rather clumsy, and it's nice to be able to call it from the class, as in 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}
In python 2, you have to import this function from the increasingly less useful string module:
>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'
Class Method
A class method is a similar to an instance method in that it takes an implicit first argument, but instead of taking the instance, it takes the class. Frequently these are used as alternative constructors for better semantic usage and it will support inheritance.
The most canonical example of a builtin classmethod is dict.fromkeys
. It is used as an alternative constructor of dict, (well suited for when you know what your keys are and want a default value for them.)
>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}
When we subclass dict, we can use the same constructor, which creates an instance of the subclass.
>>> 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'>
See the pandas source code for other similar examples of alternative constructors, and see also the official Python documentation on classmethod
and staticmethod
.
最初の引数のみが異なります:
- 通常の方法:現在のオブジェクトは (追加の) 最初の引数として自動的に渡されます
- classmethod:現在のオブジェクトのクラスが(追加の) 最初の引数として自動的に渡されます
- staticmethod:追加の引数は自動的に渡されません。関数に渡したものが得られます。
さらに詳細に...
通常の方法
すべてのオブジェクト指向言語と同様に、「標準」メソッド。オブジェクトのメソッドが呼び出されると、self
最初の引数として追加の引数が自動的に与えられます。つまり、メソッド
def f(self, x, y)
2 つの引数で呼び出す必要があります。self
は自動的に渡され、オブジェクトそのものです。this
たとえば、魔法のように現れる に似ています。java/c++ では、明示的に示されているのは python のみです。
実際には、最初の引数を呼び出す必要はありませんが
self
、それは標準的な規則であるため、そのままにしておきます
クラスメソッド
メソッドが装飾されている場合
@classmethod
def f(cls, x, y)
自動的に提供される引数は self
ではなく、 のクラスです self
。
静的メソッド
メソッドが装飾されている場合
@staticmethod
def f(x, y)
メソッドには自動引数はまったく与えられません。呼び出されるパラメータのみが与えられます。
用途
classmethod
主に代替コンストラクターに使用されます。staticmethod
オブジェクトの状態や、クラス自体の構造さえも使用しません。クラスの外部の関数である可能性があります。同様の機能を持つ関数をグループ化するためにクラス内に配置するだけです(たとえば、JavaのMath
クラスの静的メソッドなど)
class Point
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def frompolar(cls, radius, angle):
"""The `cls` argument is the `Point` class itself"""
return cls(radius * cos(angle), radius * sin(angle))
@staticmethod
def angle(x, y):
"""this could be outside the class, but we put it here
just because we think it is logically related to the class."""
return atan(y, x)
p1 = Point(3, 2)
p2 = Point.frompolar(3, pi/4)
angle = Point.angle(3, 2)
@classmethod
「いつvsを使い@staticmethod
ますか?」という質問の方が適切だと思います。
@classmethod
クラス定義に関連付けられているプライベート メンバーに簡単にアクセスできます。これは、シングルトン、または作成されたオブジェクトのインスタンス数を制御するファクトリ クラスを実行するための優れた方法です。
@staticmethod
わずかなパフォーマンスの向上を提供しますが、クラス外のスタンドアロン関数として達成できなかったクラス内の静的メソッドの生産的な使用をまだ見たことがありません。
静的メソッド:
- self 引数のない単純な関数。
- クラス属性に取り組みます。インスタンス属性ではありません。
- クラスとインスタンスの両方から呼び出すことができます。
- それらを作成するには、組み込み関数の staticmethod() を使用します。
静的メソッドの利点:
- クラススコープで関数名をローカライズします
- 関数コードを使用する場所に近づけます
各メソッドを特別にインポートする必要がないため、モジュールレベルの関数よりもインポートが便利
@staticmethod def some_static_method(*args, **kwds): pass
クラス メソッド:
- クラス名として最初の引数を持つ関数。
- クラスとインスタンスの両方から呼び出すことができます。
これらは組み込み関数の classmethod で作成されます。
@classmethod def some_class_method(cls, *args, **kwds): pass
@decoratorsはpython2.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)
また、これはクラスメソッドと静的メソッドを使用するための良い例であることに注意してください。静的メソッドは、クラスClusterを内部で使用するため、明らかにクラスに属しています。classmethodにはクラスに関する情報のみが必要であり、オブジェクトのインスタンスは必要ありません。
メソッドをclassmethodにすることの別の利点は_is_cluster_for
、サブクラスがその実装を変更することを決定できることです。おそらく、それはかなり一般的で、複数のタイプのクラスターを処理できるため、クラスの名前を確認するだけでは不十分です。
@staticmethod
メソッド記述子としてのデフォルト関数を無効にするだけです。classmethod は、所有するクラスへの参照を最初の引数として渡すコンテナー callable で関数をラップします。
>>> 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 で静的メソッド、クラス メソッド、または抽象メソッドを使用する方法に関する決定的なガイドは、このトピックへの 1 つの適切なリンクであり、次のように要約されています。
@staticmethod
関数は、クラス内で定義された関数にすぎません。最初にクラスをインスタンス化せずに呼び出すことができます。その定義は継承によって不変です。
- Python は、オブジェクトのバインドされたメソッドをインスタンス化する必要はありません。
- コードの可読性が向上し、オブジェクト自体の状態に依存しません。
@classmethod
関数はクラスをインスタンス化せずに呼び出すこともできますが、その定義は親クラスではなくサブクラスに従います。継承により、サブクラスによってオーバーライドできます。これは、@classmethod
関数の最初の引数が常にcls (クラス) でなければならないためです。
- たとえば、ある種の前処理を使用してクラスのインスタンスを作成するために使用されるファクトリ メソッド。
- 静的メソッドを呼び出す静的メソッド: 静的メソッドを複数の静的メソッドに分割する場合は、クラス名をハードコードするのではなく、クラス メソッドを使用する必要があります。
staticmethod と classmethod に関するもう 1 つの考慮事項は、継承です。次のクラスがあるとします。
class Foo(object):
@staticmethod
def bar():
return "In Foo"
bar()
次に、子クラスでオーバーライドします。
class Foo2(Foo):
@staticmethod
def bar():
return "In Foo2"
これは機能しbar()
ますが、子クラス ( Foo2
) の実装では、そのクラスに固有のものを利用できなくなっていることに注意してください。たとえば、 の実装で使用したいFoo2
というメソッドがあったとします。magic()
Foo2
bar()
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"
ここでの回避策は を呼び出すことFoo2.magic()
ですbar()
が、同じことを繰り返すことになります ( の名前が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
また: 歴史的なメモ: Guido Van Rossum (Python の作成者) はかつてstaticmethod
「事故」と呼ばれていました: https://mail.python.org/pipermail/python-ideas/2012-May/014969.html
静的メソッドがいかに制限されているかは誰もが知っています。(それらは基本的に偶然です。私が新しいスタイルのクラスと記述子を発明していた Python 2.2 の時代にさかのぼります。私はクラス メソッドを実装するつもりでしたが、最初はそれらを理解できず、誤って最初に静的メソッドを実装してしまいました。それらを削除してクラスメソッドのみを提供するには遅すぎました。
また: https://mail.python.org/pipermail/python-ideas/2016-July/041189.html
正直なところ、staticmethod は何かの間違いでした。私は Java クラス メソッドのようなものを作ろうとしていましたが、それがリリースされると、本当に必要なのは classmethod であることがわかりました。しかし、静的メソッドを取り除くには遅すぎました。
例を使用して基本的な違いを説明しようとします。
class A(object):
x = 0
def say_hi(self):
pass
@staticmethod
def say_hi_static():
pass
@classmethod
def say_hi_class(cls):
pass
def run_self(self):
self.x += 1
print self.x # outputs 1
self.say_hi()
self.say_hi_static()
self.say_hi_class()
@staticmethod
def run_static():
print A.x # outputs 0
# A.say_hi() # wrong
A.say_hi_static()
A.say_hi_class()
@classmethod
def run_class(cls):
print cls.x # outputs 0
# cls.say_hi() # wrong
cls.say_hi_static()
cls.say_hi_class()
1 - 初期化せずに静的メソッドとクラスメソッドを直接呼び出すことができます
# A.run_self() # wrong
A.run_static()
A.run_class()
2-静的メソッドは自己メソッドを呼び出すことはできませんが、他の静的およびクラスメソッドを呼び出すことはできます
3-静的メソッドはクラスに属し、オブジェクトをまったく使用しません。
4- クラス メソッドは、オブジェクトではなくクラスにバインドされます。
と の純粋な Python バージョンを提供すると、言語レベルでの違いを理解するのに役立つstaticmethod
と思います。classmethod
どちらも非データ記述子です (最初に記述子に慣れていると理解しやすいでしょう)。
class StaticMethod(object):
"Emulate PyStaticMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
def __get__(self, obj, objtype=None):
return self.f
class ClassMethod(object):
"Emulate PyClassMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
def __get__(self, obj, cls=None):
def inner(*args, **kwargs):
if cls is None:
cls = type(obj)
return self.f(cls, *args, **kwargs)
return inner
名前が示すように、クラス メソッドは、オブジェクトではなくクラスを変更するために使用されます。クラスを変更するには、クラスを更新する方法であるため、クラスの属性 (オブジェクトの属性ではない) を変更します。これが、クラス メソッドが最初の引数としてクラス (慣習的に「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."
まず、両方の概念を理解するために使用するサンプル コードから始めましょう。
class Employee:
NO_OF_EMPLOYEES = 0
def __init__(self, first_name, last_name, salary):
self.first_name = first_name
self.last_name = last_name
self.salary = salary
self.increment_employees()
def give_raise(self, amount):
self.salary += amount
@classmethod
def employee_from_full_name(cls, full_name, salary):
split_name = full_name.split(' ')
first_name = split_name[0]
last_name = split_name[1]
return cls(first_name, last_name, salary)
@classmethod
def increment_employees(cls):
cls.NO_OF_EMPLOYEES += 1
@staticmethod
def get_employee_legal_obligations_txt():
legal_obligations = """
1. An employee must complete 8 hours per working day
2. ...
"""
return legal_obligations
クラスメソッド
クラス メソッドは、クラス自体を暗黙の引数として受け入れ、オプションで、定義で指定されたその他の引数を受け入れます。クラス メソッドはオブジェクト インスタンスにアクセスできないことを理解することが重要です (インスタンス メソッドのように)。したがって、クラス メソッドを使用してインスタンス化されたオブジェクトの状態を変更することはできませんが、代わりに、そのクラスのすべてのインスタンス間で共有されるクラスの状態を変更できます。クラス メソッドは通常、クラス自体にアクセスする必要がある場合に役立ちます。たとえば、クラスのインスタンスを作成するメソッドであるファクトリ メソッドを作成する場合などです。つまり、クラス メソッドは代替コンストラクターとして機能できます。
サンプル コードでは、Employee
3 つの引数を指定することで のインスタンスを作成できます。first_name
、last_name
およびsalary
。
employee_1 = Employee('Andrew', 'Brown', 85000)
print(employee_1.first_name)
print(employee_1.salary)
'Andrew'
85000
ここで、従業員の名前が、姓と名が空白で区切られた 1 つのフィールドで提供される可能性があると仮定しましょう。この場合、employee_from_full_name
合計 3 つの引数を受け取るクラス メソッドを使用できます。最初のものはクラス自体であり、メソッドを呼び出すときに提供されないことを意味する暗黙の引数です — Python は自動的にこれを行います:
employee_2 = Employee.employee_from_full_name('John Black', 95000)
print(employee_2.first_name)
print(employee_2.salary)
'John'
95000
employee_from_full_name
このコンテキストではあまり意味がありませんが、オブジェクト インスタンスから呼び出すことも可能であることに注意してください。
employee_1 = Employee('Andrew', 'Brown', 85000)
employee_2 = employee_1.employee_from_full_name('John Black', 95000)
クラス メソッドを作成するもう 1 つの理由は、クラスの状態を変更する必要がある場合です。この例では、クラス変数NO_OF_EMPLOYEES
は、会社で現在働いている従業員の数を追跡します。このメソッドは、Employee の新しいインスタンスが作成されるたびに呼び出され、それに応じてカウントを更新します。
employee_1 = Employee('Andrew', 'Brown', 85000)
print(f'Number of employees: {Employee.NO_OF_EMPLOYEES}')
employee_2 = Employee.employee_from_full_name('John Black', 95000)
print(f'Number of employees: {Employee.NO_OF_EMPLOYEES}')
Number of employees: 1
Number of employees: 2
静的メソッド
一方、静的メソッドでは、インスタンス (つまりself
) もクラス自体 (つまりcls
) も暗黙の引数として渡されません。これは、そのようなメソッドがクラス自体またはそのインスタンスにアクセスできないことを意味します。静的メソッドは、クラスのメンバーとして追加する代わりにヘルパー モジュールに配置することもできるため、クラスのコンテキストでは役に立たないと主張することができます。オブジェクト指向プログラミングでは、クラスを論理チャンクに構造化することが重要です。そのため、論理的にクラスに属しているという理由だけでクラスの下にメソッドを追加する必要がある場合、静的メソッドは非常に便利です。この例では、という名前の静的メソッドget_employee_legal_obligations_txt
会社のすべての従業員の法的義務を含む文字列を返すだけです。この関数は、クラス自体やインスタンスとは対話しません。別のヘルパー モジュールに配置することもできますが、このクラスにのみ関連するため、Employee クラスの下に配置する必要があります。
静的メソッドは、クラス自体から直接アクセスできます
print(Employee.get_employee_legal_obligations_txt())
1. An employee must complete 8 hours per working day
2. ...
またはクラスのインスタンスから:
employee_1 = Employee('Andrew', 'Brown', 85000)
print(employee_1.get_employee_legal_obligations_txt())
1. An employee must complete 8 hours per working day
2. ...
参考文献
staticmethod は、継承階層内のオブジェクト、クラス、または親クラスの属性にアクセスできません。クラスで直接 (オブジェクトを作成せずに) 呼び出すことができます。
classmethod は、オブジェクトの属性にアクセスできません。ただし、継承階層内のクラスおよび親クラスの属性にアクセスできます。クラスで直接 (オブジェクトを作成せずに) 呼び出すことができます。オブジェクトで呼び出された場合は、通常のメソッドと同じで、アクセスせずself.<attribute(s)>
にアクセスするself.__class__.<attribute(s)>
だけです。
を持つクラスがあるb=2
とします。オブジェクトを作成し、これをその中に再設定しb=4
ます。staticmethod は以前から何もアクセスできません。.b==2
クラスメソッドは、経由でのみアクセスできますcls.b
。通常の方法では、 .b==4
viaself.b
と.b==2
viaの両方にアクセスできますself.__class__.b
。
KISS のスタイルに従うこともできます (シンプルに、ばかげてください): staticmethods と classmethods を使用しないでください。インスタンス化せずにクラスを使用しないでください。オブジェクトの属性のみにアクセスしてくださいself.attribute(s)
。OOP がそのように実装されている言語があり、それは悪い考えではないと思います。:)
iPythonで他の点では同一のメソッドをすばやくハックアップすると、@staticmethod
パフォーマンスがわずかに向上することがわかります(ナノ秒単位)が、それ以外の場合は機能しないようです。また、パフォーマンスの向上は、staticmethod()
コンパイル中にメソッドを処理する追加の作業(スクリプトを実行するときにコードが実行される前に発生します)によっておそらく消去されます。
@staticmethod
コードを読みやすくするために、ナノ秒が重要な大量の作業にメソッドが使用されない限り、避けたいと思います。