14

次のようなPythonアプリケーションがあります。

global_counter = 0
connections = {}

class SocketHandler():
    currentid = 0
    def open(self):
        global global_counter
        global connections
        currentid = global_counter
        global_counter += 1
        connections[currentid] = self
        print "WebSocket " + str(currentid) + " opened"

    def on_close(self):
        global connections
        print "WebSocket " + str(currentid) + " closed"
        del connections[currentid]

エラーが発生します:

NameError: global name 'currentid' is not defined

「open」と「on_close」の行で、接続を開いている/閉じていることを出力します。クラスで定義しましたが、なぜスコープ外なのですか。また、グローバル変数を使用するのは悪いことだと読みましたが、これを回避する方法がわかりません。誰かが私が何をすべきかを指摘できますか? ありがとう。

4

3 に答える 3

17

Python では、メソッド内の属性に暗黙的にアクセスすることはできません。

行のような裸の名前currentid:

del connections[currentid]

グローバルモジュールスコープを試す前に、常にローカル関数スコープで名前を検索し、次に各囲み関数スコープで名前を検索します (そして、最後の手段として組み込み関数を検索します)。currentidこれらのスコープのいずれにも見つからないクラス属性です。

Python で属性を検索するには、検索するオブジェクトを常に指定する必要があります。ルックアップ プロトコルは、オブジェクトが必ずしも属性自体を持っている必要がないことを意味します。属性ルックアップは、指定したオブジェクトのクラス (および継承が含まれる場合は基本クラス) にフォールバックします。

したがって、これは機能します:

del connections[self.currentid]

ただし、コードの残りの部分も、あなたが思っていることを行っているとは思いません。メソッドのこの行open

currentid = global_counter

オブジェクトのcurrentid属性を設定しません。明示的に宣言しない限りSocketHandler、裸の名前に割り当てると、常にローカル変数に割り当てられます(キーワードglobalを使用したため、これに気付いているようです)。globalしたがって、openメソッドでcurrentidは、ローカル関数変数です。その値はopenメソッドの最後で失われます。

実際、SocketHandlerオブジェクトにはcurrentid属性がまったくありません (表示されていないコードが他にない限り)。class ブロックを入れても、すべてのインスタンスに属性currentid = 0が付与されるわけではありません。クラス自体に属性を与えます。これは、ブロックが個々のインスタンスではなく、クラス オブジェクトに属性を作成する (関数を格納する) のと同じです。SocketHandlercurrentidSocketHandlercurrentiddef open(self):open

self.currentidメソッドを読み込んでもobject内の属性on_closeを見つけることができないため、Python は のクラスを調べます。そのオブジェクトに値があるため、以前に実行したかどうかに関係なく、読み取りの結果は になります。currentidselfselfSocketHandlercurrentidself.currentid0openSocketHandler

currentidをインスタンス変数として eachに格納する場合SocketHandler、行は次のようにopenする必要があります。

self.currentid = global_counter

currentidこれは、 によって参照されるオブジェクトの属性に割り当てられますselfcurrentidまた、メソッド内の他のすべての参照を に変更する必要がありますself.currentid

于 2012-10-08T22:21:44.177 に答える
5

currentidそれはself.currentidクラス変数であるためです。

于 2012-10-08T22:04:07.803 に答える
1

currentidはインスタンス属性なので、self.currentid代わりに使用しますcurrentid:

def on_close(self):
        global connections
        print "WebSocket " + str(self.currentid) + " closed"
        del connections[self.currentid]
于 2012-10-08T22:04:33.913 に答える