Ich habe eine Python-Anwendung, die wie folgt lautet:

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]

Ich erhalte den Fehler:

NameError: global name 'currentid' is not defined

In den Zeilen "open" und "on_close", in denen ich drucke, dass ich die Verbindung öffne / schließe. Ich habe es in der Klasse definiert, warum ist es nicht im Umfang. Ich habe auch gelesen, dass die Verwendung globaler Variablen schlecht ist, aber ich sehe keinen Weg, dies zu umgehen. Kann jemand darauf hinweisen, was ich tun soll? Vielen Dank.

11
Lylax 9 Okt. 2012 im 02:03

3 Antworten

Beste Antwort

Sie haben in Python keinen impliziten Zugriff auf Attribute in Methoden.

Ein nackter Name wie currentid in der Zeile:

del connections[currentid]

Sucht immer nach einem Namen im lokalen Funktionsbereich und dann in jedem umschließenden Funktionsbereich, bevor der globale Modulbereich ausprobiert wird (und betrachtet dann die integrierten Funktionen als letzten Ausweg). currentid ist ein Klassenattribut, das in keinem dieser Bereiche gefunden wird.

Um ein Attribut in Python nachzuschlagen, müssen Sie immer ein Objekt angeben, in dem gesucht werden soll. Obwohl das Suchprotokoll bedeutet, dass das Objekt nicht unbedingt das Attribut selbst haben muss; Die Attributsuche greift auf die Klasse des von Ihnen angegebenen Objekts zurück (und auf die Basisklassen, wenn die Vererbung betroffen ist).

Das würde also funktionieren:

del connections[self.currentid]

Ich glaube jedoch nicht, dass der Rest Ihres Codes das tut, was Sie denken. Diese Zeile in der Methode open:

currentid = global_counter

Setzt das currentid -Attribut Ihres SocketHandler -Objekts nicht. Zuweisen zu einem bloßen Namen immer wird einer lokalen Variablen zugewiesen, es sei denn, Sie deklarieren sie explizit als global (Sie scheinen sich dessen bewusst zu sein, da Sie das Schlüsselwort global verwendet haben ). In der open -Methode ist currentid also eine lokale Funktionsvariable. Sein Wert geht am Ende der open -Methode verloren.

Tatsächlich haben Ihre SocketHandler Objekte überhaupt kein currentid -Attribut (es sei denn, es gibt mehr Code, den Sie uns nicht gezeigt haben). Wenn Sie currentid = 0 in den Klassenblock einfügen, erhalten nicht alle SocketHandler Instanzen ein currentid -Attribut. Es gibt der SocketHandler Klasse selbst ein Attribut currentid; Dies ist genau so, wie der def open(self): -Block ein open -Attribut (Speichern einer Funktion) für das Klassenobjekt erstellt, nicht für jede einzelne Instanz.

Wenn Sie self.currentid in der on_close -Methode lesen, wird kein currentid -Attribut im Objekt self gefunden, sodass Python die Klasse von self betrachtet, die {ist {X5}}. Dieses Objekt hat einen Wert von currentid, sodass das Ergebnis des Lesens von self.currentid 0 ist, unabhängig davon, ob Sie zuvor open ausgeführt haben oder nicht. auf diesem SocketHandler.

Wenn Sie currentid als Instanzvariable in jedem SocketHandler speichern möchten, muss die Zeile in open wie folgt lauten:

self.currentid = global_counter

Dies wird dem Attribut currentid des Objekts zugewiesen, auf das self verweist. Sie müssten dann auch alle anderen Verweise auf currentid in Ihren Methoden in self.currentid ändern.

12
Ben 8 Okt. 2012 im 22:21

currentid ist ein Instanzattribut. Verwenden Sie daher self.currentid anstelle von currentid:

def on_close(self):
        global connections
        print "WebSocket " + str(self.currentid) + " closed"
        del connections[self.currentid]
1
defuz 8 Okt. 2012 im 22:04

currentid sollte self.currentid sein, da es sich um eine Klassenvariable handelt.

5
ronak 8 Okt. 2012 im 22:04