Pythonでクラスのメンバー変数にアクセスしますか?


83
class Example(object):
    def the_example(self):
        itsProblem = "problem"

theExample = Example()
print(theExample.itsProblem)

クラスの変数にアクセスするにはどうすればよいですか?私はこの定義を追加しようとしました:

def return_itsProblem(self):
    return itsProblem

しかし、それも失敗します。


1
クラス"静的"変数についての実際のタイトル編集し、質問:stackoverflow.com/questions/707380/...
チロSantilli郝海东冠状病六四事件法轮功

回答:


139

答えは、一言で言えば

あなたの例でitsProblemは、はローカル変数です。

selfインスタンス変数を設定および取得するには、を使用する必要があります。__init__メソッドで設定できます。その場合、コードは次のようになります。

class Example(object):
    def __init__(self):
        self.itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

ただし、真のクラス変数が必要な場合は、クラス名を直接使用してください。

class Example(object):
    itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)
print (Example.itsProblem)

ただし、これtheExample.itsProblemは自動的にに等しくなるように設定されExample.itsProblemますが、まったく同じ変数ではなく、個別に変更できるため、注意してください。

いくつかの説明

Pythonでは、変数を動的に作成できます。したがって、次のことができます。

class Example(object):
    pass

Example.itsProblem = "problem"

e = Example()
e.itsSecondProblem = "problem"

print Example.itsProblem == e.itsSecondProblem 

プリント

本当

したがって、それはまさに前の例で行うことです。

確かに、Pythonではとしてを使用しますselfthis、それよりも少し多いです。self最初の引数は常にオブジェクト参照であるため、はオブジェクトメソッドの最初の引数です。これは、呼び出すかどうかに関係selfなく、自動的に行われます。

つまり、次のことができます。

class Example(object):
    def __init__(self):
        self.itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

または:

class Example(object):
    def __init__(my_super_self):
        my_super_self.itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

まったく同じです。ANYオブジェクトメソッドの最初の引数は現在のオブジェクトでありself、慣例としてのみ呼び出します。そして、外部から行うのと同じ方法で、このオブジェクトに変数だけを追加します。

さて、クラス変数について。

あなたがするとき:

class Example(object):
    itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

最初にクラス変数を設定し、次にオブジェクト(インスタンス)変数にアクセスします。このオブジェクト変数を設定することはありませんが、機能します。どうすればそれが可能ですか?

さて、Pythonは最初にオブジェクト変数を取得しようとしますが、それが見つからない場合は、クラス変数を取得します。警告:クラス変数はインスタンス間で共有されますが、オブジェクト変数は共有されません。

結論として、クラス変数を使用してデフォルト値をオブジェクト変数に設定しないでください。__init__そのために使用します。

最終的には、Pythonクラスがインスタンスであり、したがってオブジェクト自体であることがわかります。これにより、上記を理解するための新しい洞察が得られます。気づいたら、戻って後でもう一度読んでください。


「theExample.itsProblemは自動的にExample.itsProblemと等しくなるように設定されますが、まったく同じ変数ではなく、個別に変更できます」-しかし、それは正しくなく、あなたの言い回しは誤解を招く恐れがあります。「それは私のことを言い換えが提案するので、私は、あなたがそこに何が起こっているか知っている信頼同じ変数が、それは、オブジェクトごとに独立してrebindedすることができます」。
jsbueno 2010

はい。ただし、バインディングは、JavaやC(OPのように思われる)などの他のプログラミング言語の概念であり、完全には不明です。次に、バインディングとは何か、次に遅延バインディング、そして可変オブジェクトの参照に関する問題について説明します。長すぎるでしょう。いつかあなたは理解の祭壇の正確さを犠牲にしなければならないと思います。
e-satis 2010

調べる価値のある@classmethodデコレータもあります(これは2.7以上かもしれません)。ここで興味深い議論- stackoverflow.com/questions/12179271/...
JSH

1
名前の束縛:レベルに関係なく、虚偽の陳述をするのは悪い考えだと思います。このわずかな編集をお勧めします。ただし、これtheExample.itsProblemは自動的にに等しく設定されるため注意してくださいExample.itsProblem。ただし、実用的な観点からは*、まったく同じ変数ではなく、個別に変更できます。*:実際には同じオブジェクトとして開始されますが、Pythonの名前バインディングを
n611x007 2014

11

クラス変数ではなく、ローカル変数を宣言しています。インスタンス変数(属性)を設定するには、

class Example(object):
    def the_example(self):
        self.itsProblem = "problem"  # <-- remember the 'self.'

theExample = Example()
theExample.the_example()
print(theExample.itsProblem)

クラス変数(別名静的メンバー)を設定するには、

class Example(object):
    def the_example(self):
        Example.itsProblem = "problem"
        # or, type(self).itsProblem = "problem"
        # depending what you want to do when the class is derived.

1
クラス変数が宣言されていることを除いて、一度クラスレベル。あなたの方法はすべてのインスタンス化でそれをリセットします、これは本当にあなたが望むものではありません。明示的な自己の背後にある理論的根拠については、stackoverflow.com / questions / 2709821 / python- self -explainedも参照してください。

2

インスタンス関数(つまり、selfを渡される関数)がある場合は、selfを使用して、を使用してクラスへの参照を取得できます。 self.__class__

たとえば、以下のコードでは、tornadoはgetリクエストを処理するインスタンスを作成しますが、get_handlerクラスを取得してそれを使用してriakクライアントを保持できるため、リクエストごとにインスタンスを作成する必要はありません。

import tornado.web
import riak

class get_handler(tornado.web.requestHandler):
    riak_client = None

    def post(self):
        cls = self.__class__
        if cls.riak_client is None:
            cls.riak_client = riak.RiakClient(pb_port=8087, protocol='pbc')
        # Additional code to send response to the request ...
    

これは、OPの元のタイトルからの質問を示すための非常に良い例です。実際には、OPの例はタイトルと一致せず、他の回答は例を参照しています。とにかく、これはDRYの原則に違反しないため、クラスレベルの変数にアクセスするための最良の方法です。他のいくつかの例のように。クラス名を繰り返すのではなく、self .__ class__を使用することをお勧めします。これにより、コードの将来性が保証され、リファクタリングが容易になります。サブクラス化をあえて使用する場合は、これにも利点があります。
MIT

上記のようなハンドラーを使用すると、シングルスレッド以外のアプリケーションだけでなく問題が発生する可能性があることに注意してください。クラスの複数のインスタンスは、理論的には同じハンドラーを並列で使用できます。ハンドラーがこれを行うように設計されていない場合(内部構造によって異なります)、機能しない可能性があります。シングルスレッドアプリケーションの「並列」とは、最初のクラスインスタンスがハンドラーの使用を終了しておらず、2番目のインスタンスがハンドラーの使用を開始することを意味します。このような場合は、代わりにインスタンス変数を使用することをお勧めします。
MIT

0

以下の例のようなreturnステートメントを実装してください!あなたは良いはずです。私はそれが誰かを助けることを願っています。

class Example(object):
    def the_example(self):
        itsProblem = "problem"
        return itsProblem 


theExample = Example()
print theExample.the_example()

1
コードのインデントを修正する必要があります。この質問に対する優れた回答もあり、あなたの回答はそれらの回答の基本的なバリエーションであり、代替の解決策ではありません...
HEADLESS_0NE 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.