Pythonのクラスメソッド内で「静的」クラス変数にアクセスするにはどうすればよいですか?


162

次のpythonコードがある場合:

class Foo(object):
    bar = 1

    def bah(self):
        print(bar)

f = Foo()
f.bah()

文句を言う

NameError: global name 'bar' is not defined

barメソッド内でクラス/静的変数にアクセスするにはどうすればよいbahですか?


Pythonと静力学に関する詳細情報は、ここにあります:stackoverflow.com/questions/68645/python-static-variable
bedwyr

回答:


166

代わりのbar使用self.barまたはFoo.bar。に割り当てるとFoo.bar静的変数self.barが作成され、to に割り当てるとインスタンス変数が作成されます。


12
Foo.barは機能しますが、self.barは静的変数ではなくインスタンス変数を作成します。
bedwyr

47
bedwyr、「print self.bar」はインスタンス変数を作成しません(ただし、self.barへの割り当ては行います)。
コンスタンティン

@Constantin-気づかなかった、興味深い違いだ。訂正をありがとう:-)
bedwyr 2009

2
ただし、ivarを使用するつもりがない場合は、Foo.classmemberを使用する方が明確です。
mk12 09/09/13

2
静的変数を使用する場合は、stackoverflow.com / questions / 68645 /…から得点を読むことをお勧めします。@Constantinは多くの落とし穴の1つを与えます。
Trevor Boyd Smith

84

クラスメソッドを定義します。

class Foo(object):
    bar = 1
    @classmethod
    def bah(cls):    
        print cls.bar

bah()インスタンスメソッドでなければならない場合(つまり、selfにアクセスできる場合)、クラス変数に直接アクセスできます。

class Foo(object):
    bar = 1
    def bah(self):    
        print self.bar

3
なぜself.__class__.barではなくFoo.barだけではないのですか?
mk12

15
@ Mk12:クラス継承がある場合、「クラス変数」は基本クラスまたはサブクラスにある可能性があります。どちらを参照しますか?何をしようとしているかに依存します。Foo.barは常に、指定されたクラスの属性を参照します。これは、基本クラスまたはサブクラスの場合があります。self.__class__.barは、インスタンスがタイプであるクラスを参照します。
Craig McQueen

7
言語の詳細に気づき、微調整された2つのユースケースを区別できるようになったとき、不幸な点に達しました。それは確かにあなたが何をしたいかに依存しますが、多くの人々はそのような機微に出席しません。
holdenweb 2011

2
ところで、これは「クラス変数」のまれな使用法です。特定のクラス(ここではFoo)で定義する方がはるかに一般的です。これは、一部の高度なプログラミング状況に役立つ情報です。しかし、ほぼ間違いなく、元の質問が回答として求めていたものではありません(この回答が必要な人は、Foo.barの実行方法をすでに知っています)。+1私はこれから何かを学んだので。
ToolmakerSteve 2013年

3
インスタンス変数とメソッドではなく、クラス変数とメソッドをいつ使用するかについて学習しています。インスタンスメソッドでクラス変数にアクセスする場合、self .__ class__.barを使用する必要がありますか?barはインスタンス変数ではなくクラス変数ですが、self.barは機能することに気づきました。
ビル

13

すべての優れた例と同様に、実際に実行しようとしていることを単純化しました。これは良いことですが、クラス変数とインスタンス変数の関係でpythonには多くの柔軟性があることは注目に値します。メソッドについても同じことが言えます。可能性の良いリストについては、MichaelFötschの新しいスタイルのクラスの紹介、特にセクション2〜6を読むことをお勧めします。

開始時に覚えるのに多くの作業が必要なことの1つは、PythonはJavaではないということです。 単なる決まり文句以上のもの。Javaでは、クラス全体がコンパイルされ、名前空間の解決が非常に単純になります。メソッドの外部(どこでも)に宣言された変数はインスタンス(または静的な場合はクラス)変数であり、メソッド内で暗黙的にアクセスできます。

pythonでは、大まかな経験則として、変数を検索するために3つの名前空間が順番に検索されます。

  1. 関数/メソッド
  2. 現在のモジュール
  3. ビルトイン

{begin pedagogy}

これには限られた例外があります。私に発生する主なものは、クラス定義がロードされているとき、クラス定義はそれ自体の暗黙的な名前空間であるということです。しかし、これはモジュールがロードされている間だけ続き、メソッド内では完全にバイパスされます。したがって:

>>> class A(object):
        foo = 'foo'
        bar = foo


>>> A.foo
'foo'
>>> A.bar
'foo'

だが:

>>> class B(object):
        foo = 'foo'
        def get_foo():
            return foo
        bar = get_foo()



Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    class B(object):
  File "<pyshell#11>", line 5, in B
    bar = get_foo()
  File "<pyshell#11>", line 4, in get_foo
    return foo
NameError: global name 'foo' is not defined

{end pedagogy}

最後に、覚えておくべき事は、あなたがいることであるアクセスしたい変数のいずれかへのアクセス権を持っていますが、おそらくない暗黙のうちに。目標が単純で単純な場合は、おそらくFoo.barまたはself.barで十分です。例がさらに複雑になった場合、または継承などの豪華なことをしたい場合(静的/クラスのメソッドを継承できます!)、またはクラス自体の中でクラスの名前を参照するという考えは間違っているようです。リンクしたイントロ


IIRC、技術的には3(+)の名前空間が検索されます-関数ローカル、モジュール/グローバル、および組み込み。ネストされたスコープは、複数のローカルスコープが検索される可能性があることを意味しますが、これは例外的なケースの1つです。(...)
ジェフシャノン

それは、関数の入ったモジュールであるとしても、私はのは、検索されないことを、「メインモジュール」を言って、慎重になるだろう、メインモジュール...とインスタンスの参照から属性を検索することは別物ですが、この答えは説明しない理由インスタンス/クラス参照が必要です。
ジェフシャノン


-2
class Foo(object):    
    bar = 1

    def bah(object_reference):
        object_reference.var = Foo.bar
        return object_reference.var


f = Foo() 
print 'var=', f.bah()

4
このコードは問題を解決する可能性がありますが、これが問題を解決する方法と理由の説明含めると、投稿の品質が向上し、おそらく投票数が増えることになります。あなたが今尋ねている人だけでなく、あなたが将来の読者のための質問に答えていることを忘れないでください。回答を編集して説明を追加し、適用される制限と前提を示してください。口コミから
ダブルビープ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.