Pythonで静的メソッドを使用する利点は何ですか?


90

私はコードでPythonでアンバウンドメソッドエラーに遭遇しました

import random

class Sample(object):
'''This class defines various methods related to the sample'''

    def drawSample(samplesize,List):
        sample=random.sample(List,samplesize)
        return sample

Choices=range(100)
print Sample.drawSample(5,Choices)

ここで多くの役立つ投稿を読んだ後@staticmethod、コードを機能させるために上記を追加する方法を考えました。私はPython初心者です。静的メソッドを定義したい理由を誰かが説明できますか?または、すべてのメソッドが静的メソッドとして定義されていないのはなぜですか?


1
これは奇妙な質問です。静的メソッドは設計上必要です。それは「利点」ではありません。あなたがしなければならないのであなたはそれらを使用します。静的メソッドを持つことはクラスの設計機能です。そもそも静的メソッドとは何かを尋ねていますか?質問は、あなたが知る必要があることをより明確に定義するために言い換えることができると思います。
S.Lott 2010年

15
いいえ、私は彼らが何であるか知りたくありませんでした。私が知りたかったのは、なぜそれが「必需品」なのかということでした。それは他の人の答えから明らかになりました。それは、非静的メソッドではなく、それを定義するときです。ありがとう。
Curious2learn 2010年

3
@ S.Lott:通常のクラスメソッドを使用するのではなく、静的メソッドを使用する必要があるのはいつですか?私の知る限り、クラスメソッドはstaticmethodが実行できるすべてのことを実行できます。Staticmethodはこの記事にリストされているよう「利点」を持っていませんが、私は"tはそれゆえに必要作り、クラスメソッドは静的メソッドを使用することができることを任意の場所で使用することができない理由の任意の理由を見ることができます。
RFV

回答:


128

静的メソッドは、クラスのインスタンスの属性にアクセスできないため(通常のメソッドのように)、クラス自体の属性にアクセスできないため(クラスメソッドのように)、使用が制限されています。 )。

したがって、それらは日常の方法には役立ちません。

ただし、提供されたパラメーター(およびモジュールに対してグローバルな属性)以外の情報にアクセスする必要のないクラス(たとえば、あるタイプから別のタイプへの単純な変換)と一緒にいくつかのユーティリティ関数をグループ化すると便利です。 )

それらはクラスの外に置くこともできますが、クラス内でグループ化することは、そこでのみ適用できる場合に意味があります。

モジュール名ではなく、インスタンスまたはクラスを介してメソッドを参照することもできます。これにより、読者はメソッドがどのインスタンスに関連しているかを理解するのに役立ちます。


8
@ Curious2learn:ないすべての、しかし、いくつかの方法は、静的メソッドとして有用です。Localeインスタンスがロケールになるサンプルクラスについて考えてみてください(duh)。getAvailableLocales()この方法は、そのようなクラスの静的メソッドの良い例だろう。それははっきりLocaleクラスに属し、また明確に任意の特定のインスタンスに属していないながら。
MestreLion 2012年

...そして、クラスのメソッドにアクセスする必要がない可能性があるため、クラスメソッドでもありません。
MestreLion 2012年

編集者は、静的メソッドは、またはではなく、から明示的にナビゲートすることにより、クラス属性にアクセスできると指摘しています。これは「パブリック」属性にも当てはまります。慣例により、この方法で、アンダースコアで非表示になっている属性や、2つのアンダースコアでマングルされた名前にアクセスしないでください。また、属性が継承階層の場所を移動すると、コードがより脆弱になることも意味します。class_name.attributecls.attributeself.attribute
2017

staticmethodsをいつ使用するかを決定するのに役立つGuidoからの引用(決して):「静的メソッドがどれほど制限されているかは誰もが知っています(基本的には偶然です—新しいスタイルのクラスと記述子を発明していたPython2。2日で、クラスメソッドを実装する
つもりでした

189

この記事を参照してくださいな説明を。

TL; DR

1.それはの使用を排除します self引数ます。

2.Pythonがインスタンス化れた各オブジェクトのbound-methodをインスタンス化する必要がないため、メモリ使用量が削減されます。

>>>RandomClass().regular_method is RandomClass().regular_method
False
>>>RandomClass().static_method is RandomClass().static_method
True
>>>RandomClass.static_method is RandomClass().static_method
True

3.コードの可読性が向上し、メソッドがオブジェクト自体の状態に依存しないことを意味します。

4.メソッドがモジュールレベルで(つまり、クラスの外部で)定義されている場合、サブクラスがそのメソッドをオーバーライドできないという点で、メソッドのオーバーライドが可能になります。


3
これは受け入れられた答えでなければなりません。インスタンスの静的メソッドとクラス自体が同じオブジェクトであるという事実は、特にインスタンスが多数ある場合(たとえば、可変データベースレコードの各インスタンス)、真の利点です。
Zhuoyun Wei 2018

+1し、@ ZhuoyunWeiに同意します。静的メソッドがクラスメソッドよりも好ましい場合があるいくつかの理由を説明する答えだけです(1と3は実際には同じ理由ですが)。
アレックス

1
「なぜ静的メソッドなのか」に対する最良の答えですが、元の質問では「なぜすべてのメソッドが静的ではないのか」という質問もありました。短い「インスタンス属性へのアクセスなし」もそれをカバーします。
エシュ

IMOの唯一の本当の利点は、サブクラスでオーバーライドできることですが、それでもOOPに関して間違ったことをしているように感じますが、どのようなユースケースでそれを行いますか?
Boris Churzin

23

これはあなたの実際の質問のポイントには完全ではありませんが、あなたがPythonの初心者であると言ったので、おそらくそれは役立つでしょう、そして他の誰もまったく出てきてそれを明示的に言っていません。

メソッドを静的メソッドにすることで、上記のコードを修正することはありませんでした。私はクラスを捨てて関数を書いたでしょう:

def drawSample(samplesize,List):
    sample=random.sample(List,samplesize)
    return sample

Choices=range(100)
print drawSample(5,Choices)

関連する関数が多数ある場合は、それらをモジュールにグループ化できます。つまり、sample.pyたとえば、名前を付けた同じファイルにすべてを配置できます。その後

import sample

Choices=range(100)
print sample.drawSample(5,Choices)

または__init__、クラスにメソッドを追加して、便利なメソッドを持つインスタンスを作成します。

class Sample(object):
'''This class defines various methods related to the sample'''

    def __init__(self, thelist):
        self.list = thelist

    def draw_sample(self, samplesize):
        sample=random.sample(self.list,samplesize)
        return sample

choices=Sample(range(100))
print choices.draw_sample(5)

(また、上記の例の大文字と小文字の規則を、PEP 8で推奨されているスタイルに一致するように変更しました。)

Pythonの利点の1つは、すべてにクラスを使用する必要がないことです。これらは、クラスの目的である、メソッドに関連付ける必要のあるデータまたは状態がある場合にのみ使用できます。それ以外の場合は、関数を使用できます。これが関数の目的です。


コメントありがとうございます。この場合、描画されたサンプルで作業したいので、クラスが必要でした。いいえ、静的メソッドを使用しませんでしたが、受け取ったエラーメッセージに関する情報を検索するときにこの用語に出くわしたので、知りたいと思いました。しかし、クラスを定義せずに関数をモジュールに収集することについてのアドバイスは、私が必要とする他の関数に役立ちます。ほんとありがと。
Curious2learn 2010年

4
+1:それはOPが持っていたいくつかの誤解についての良い説明でした。そして、あなたは前もって、静的メソッドについての彼の質問に実際には答えていなかったと言って非常に正直でしたが、彼の問題はクラスをまったく必要としないと言ってはるかに良い解決策を与えました。
MestreLion 2012年

22

なぜ静的メソッドを定義したいのですか?

我々が持っていると仮定class呼ばれMath、その後

のオブジェクトを作成して、andやonのclass Math
ようなメソッドを呼び出すことは誰も望んでいません。ceilfloorfabs

だから私たちはそれらを作りますstatic

たとえば

>> Math.floor(3.14)

よりもはるかに優れています

>> mymath = Math()
>> mymath.floor(3.14)

したがって、それらは何らかの形で役立ちます。それらを使用するためにクラスのインスタンスを作成する必要はありません。

すべてのメソッドが静的メソッドとして定義されていないのはなぜですかですか?

インスタンス変数にアクセスすることはできません。

class Foo(object):
    def __init__(self):
        self.bar = 'bar'

    def too(self):
        print self.bar

    @staticmethod
    def foo():
        print self.bar

Foo().too() # works
Foo.foo() # doesn't work

そのため、すべてのメソッドを静的にするわけではありません。


10
しかし、なぜパッケージ計算をしないのですか?Pythonにはそのためのパッケージがあり、名前空間を作成するためにクラス定義は必要ありません。
エクストラネオン2010年

6
@extraneon:うん、わかってるけど、説明のためにシンプルでなじみのあるものが欲しかったので、を使ったMath。だから私は大文字にしましたM
Pratik Deoghare 2010年

6
OPは静的メソッドとは何かを尋ねませんでした。彼は彼らの利点は何であるか尋ねました。あなたはそれらがどのように役立つかではなく、それらの使い方を説明しています。あなたの特定の例では、名前空間ははるかに理にかなっています。
ハビエル

4
-1:適切で正しい説明ですが、選択が非常に不十分な例です。Mathそもそもクラスになる理由はないので、モジュールの方が適しています。「誰もオブジェクトを作成したくない」というクラスではなく、クラスとして意味のあるクラスの例を見つけてください。
MestreLion 2012年

3
そして、その後のための合法的なユースケースの例与える1(またはいくつかの静的であると、クラスのメソッドの)を、すべてではありません。場合は、すべてのクラスのメソッドのは静的で、クラスモジュールでなければなりません。場合はどれも、静的ではない、あなたは質問に答えるされていません。
MestreLion 2012年

13

オブジェクトインスタンスから関数オブジェクトを呼び出すと、それは「バインドされたメソッド」になり、インスタンスオブジェクト自体が最初の引数として渡されるようになります。

classmethodオブジェクトインスタンスでオブジェクト(関数オブジェクトをラップする)を呼び出すと、インスタンスオブジェクトのクラスが最初の引数として渡されます。

staticmethodオブジェクト(関数オブジェクトをラップする)を呼び出すとき、暗黙の最初の引数は使用されません。

class Foo(object):

    def bar(*args):
        print args

    @classmethod
    def baaz(*args):
        print args

    @staticmethod
    def quux(*args):
        print args

>>> foo = Foo()

>>> Foo.bar(1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with Foo instance as first argument (got int instance instead)
>>> Foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> Foo.quux(1,2,3)
(1, 2, 3)

>>> foo.bar(1,2,3)
(<Foo object at 0x1004a4510>, 1, 2, 3)
>>> foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> foo.quux(1,2,3)
(1, 2, 3)

3
+1:最後に、静的メソッドクラスメソッドとは何かについてのすばらしい説明です。あなたは説明しなかったが、なぜ1は、これまでの静的メソッドを使用したいと思う、少なくとも、あなたは明らかに両者がどのような簡単な例で説明しているより良いん公式ドキュメントより。
MestreLion 2012年

3

静的メソッドは、メソッドが属するオブジェクトのインスタンスを宣言する必要がないため、優れています。

pythonのサイトには、静的メソッドに関するいくつかの優れたドキュメントがあります:http
//docs.python.org/library/functions.html#staticmethod


デビッドに感謝します。しかし、インスタンスでも機能するため、すべてのメソッドを静的メソッドとして定義しないのはなぜですか。そうすることの欠点はありますか?
Curious2learn 2010年

4
@ Curious2learn:いいえ、静的メソッドではインスタンスにアクセスできません:インスタンスはそのクラスを除いて無視されます。
Felix Kling 2010年

4
その議論は、関数がそれ自体では生きられないが、常にクラスのコンテキストで定義されるJavaでは当てはまります。しかし、Pythonでは、関数と静的クラス関数を持つことができます。この答えは、クラスにないメソッドの代わりに静的メソッドを選択する理由を実際には示していません。
extraneon

1
@ extraneon-それはコードの組織的な好みの問題です。静的メソッドがあると、1つに追加のオプションがあります。
チャールズ・ダフィー

@ Felix-ありがとう。これにより、すべてのメソッドが静的メソッドであってはならない理由が明確になります。
Curious2learn 2010年

3

選択肢はstaticmethod:あるclassmethodinstancemethodfunction。これらが何であるかわからない場合は、最後のセクションまでスクロールダウンしてください。astaticmethodがこれらの選択肢のいずれよりも優れているかどうかは、それがどのような目的で書かれているかによって異なります。

Python静的メソッドの利点

  • クラスまたはインスタンスの属性またはメソッドにアクセスする必要がない場合staticmethodは、classmethodまたはよりもaの方が適していますinstancemethod。そうすれ@staticmethodば、クラスとインスタンスの状態が読み取られたり変更されたりしないことが(デコレータから)明らかです。ただし、を使用するとfunction、その区別がさらに明確になります(欠点を参照)。
  • aの呼び出し署名は、staticmethodaclassmethodまたはの呼び出し署名と同じです。instancemethodつまり、<instance>.<method>(<arguments>)です。したがって、後でまたは派生クラスで必要になった場合は、3つのうちの1つに簡単に置き換えることができます。あなたは単純なものではそれを行うことはできませんfunction
  • staticmethod代わりにAを使用functionして、主観的にクラスに属していることを明確にし、名前空間の競合を防ぐことができます。

Python静的メソッドの欠点

  • インスタンスまたはクラスの属性またはメソッドにアクセスすることはできません。
  • aの呼び出し署名はstaticmethodclassmethodまたはの呼び出し署名と同じinstancemethodです。これにより、staticmethodが実際にオブジェクト情報を読み取ったり変更したりしないという事実が隠されます。これにより、コードが読みにくくなります。なぜ単に使用しないのfunctionですか?
  • Astaticmethodが定義されたクラス/インスタンスの外部から呼び出す必要がある場合、Aを再利用することは困難です。再利用の可能性がある場合は、function選択することをお勧めします。
  • staticmethod人々は1がそれを読むために少し時間がかかることが含まれるコードを読み込むのでめったに使用されません。

Pythonの静的メソッドの代替

の利点について話し合うにはstaticmethod、代替案とは何か、およびそれらが互いにどのように異なるかを知る必要があります。

  • staticmethodクラスに属するが、アクセスしたり、任意のインスタンスまたはクラスの情報を変更することはできません。

これには3つの選択肢があります。

  • classmethod呼び出し側のクラスへのアクセス権を持っています。
  • instancemethod呼び出し側のインスタンスとそのクラスへのアクセス権を持っています。
  • functionクラスとは何の関係もありません。に最も近い機能staticmethodです。

これがコードでどのように見えるかを次に示します。

# function
# has nothing to do with a class
def make_cat_noise(asker_name):
    print('Hi %s, mieets mieets!' % asker_name)

# Yey, we can make cat noises before we've even defined what a cat is!
make_cat_noise('JOey')  # just a function

class Cat:
    number_of_legs = 4

    # special instance method __init__
    def __init__(self, name):
        self.name = name

    # instancemethod
    # the instance (e.g. Cat('Kitty')) is passed as the first method argument
    def tell_me_about_this_animal(self, asker_name):
        print('Hi %s, This cat has %d legs and is called %s'
              % (asker_name, self.number_of_legs, self.name))

    # classmethod
    # the class (e.g. Cat) is passed as the first method argument
    # by convention we call that argument cls
    @classmethod
    def tell_me_about_cats(cls, asker_name):
        print("Hi %s, cats have %d legs."
              % (asker_name, cls.number_of_legs))
        # cls.name  # AttributeError because only the instance has .name
        # self.name  # NameError because self isn't defined in this namespace

    # staticmethod
    # no information about the class or the instance is passed to the method
    @staticmethod
    def make_noise(asker_name):
        print('Hi %s, meooow!' % asker_name)
        # class and instance are not accessible from here

# one more time for fun!
make_cat_noise('JOey')  # just a function

# We just need the class to call a classmethod or staticmethod:
Cat.make_noise('JOey')  # staticmethod
Cat.tell_me_about_cats('JOey')  # classmethod
# Cat.tell_me_about_this_animal('JOey')  # instancemethod -> TypeError

# With an instance we can use instancemethod, classmethod or staticmethod
mycat = Cat('Kitty')  # mycat is an instance of the class Cat
mycat.make_noise('JOey')  # staticmethod
mycat.tell_me_about_cats('JOey')  # classmethod
mycat.tell_me_about_this_animal('JOey')  # instancemethod

1

名前空間関数は優れているため(以前に指摘したように):

  1. オブジェクトの状態を変更しないメソッドについて明示的にしたい場合は、静的メソッドを使用します。これは、私のチームの人々がそれらのメソッドでオブジェクトの属性を変更し始めることを思いとどまらせます。

  2. 本当に腐ったコードをリファクタリングするときは@staticmethod、できるだけ多くのメソッドを作成することから始めます。これにより、これらのメソッドをクラスに抽出できます。同意しますが、これはめったに使用しないものであり、何度か役に立ちました。


1

私の見積もりでは、sを使用することによる単一のパフォーマンス上の利点は@staticmethod、関数をクラスの外部で定義し、そうでない場合はクラスから分離することと比較してありません@staticmethod

私が言う唯一のことは彼らの存在を正当化するのは便利さです。静的メソッドは他の一般的なプログラミング言語では一般的ですが、Pythonを使用しないのはなぜですか?作成するクラスと非常に密接に関連する動作を持つ関数を作成したいが、クラスのインスタンスの内部データに実際にアクセス/変更しない場合は、それを典型的なものとして概念化することを正当化します。次に、そのクラスのメソッドをその@staticmethod上で叩くと、コードを読んでいる人は誰でも、メソッドの性質とクラスとの関係についてすぐに多くのことを学ぶことができます。

私が時々やりたいことの1つは、クラスが内部で頻繁に使用する機能をプライベートに配置すること@staticmethodです。そうすれば、モジュールによって公開されたAPIを、モジュールを使用している人が使用することはもちろん、見る必要のないメソッドで乱雑にすることもありません。


0

静的メソッドには、Pythonに存在する理由はほとんどありません。インスタンスメソッドまたはクラスメソッドのいずれかを使用します。

def method(self, args):
    self.member = something

@classmethod
def method(cls, args):
    cls.member = something

@staticmethod
def method(args):
    MyClass.member = something
    # The above isn't really working
    # if you have a subclass

あなたは「ほぼ」と言いました。それらが代替案よりも優れている可能性がある場所はありますか?
ハビエル

@Javier:考えられませんが、おそらく1つあります。それ以外の場合、なぜそのメソッドがPythonライブラリに含まれるのでしょうか。
ゲオルクSchölly

1
@ Javier、@ George:Pythonコーパスには問題がないことを確信しています。
チャールズメリアム2010年

-1:この答えは存在しない任意ののユースケースstaticmethodあらゆるものの説明classmethodや理由、それは静的なものより「より良い」である方法ですが。
MestreLion 2012年

@CharlesMerriam:もちろん、静的メソッドには使用法があります。そうしないと、Python 3(レガシーのくだらないもののほとんどが削除された)で削除または非推奨になります。ありません、単一に対する言葉staticmethod、それは嫌なものであることをあなたの主張をサポートするためのドキュメントで、またはGeorgの請求classmethod代わりに使用する必要がありますが)。
MestreLion 2012年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.