wake-up-neo.com

Verstehe nicht, warum UnboundLocalError auftritt

Was mache ich hier falsch?

counter = 0

def increment():
  counter += 1

increment()

Der obige Code wirft ein UnboundLocalError.

144
Randomblue

Python hat keine Variablendeklarationen, daher muss es das scope der Variablen selbst herausfinden. Dies geschieht nach einer einfachen Regel: Wenn einer Variablen innerhalb einer Funktion eine Zuweisung vorliegt, wird diese Variable als lokal betrachtet.[1] Also die Leitung

counter += 1

macht counter implizit zu increment(). Beim Versuch, diese Zeile auszuführen, wird jedoch versucht, den Wert der lokalen Variablen counter zu lesen, bevor er zugewiesen wird, was zu einem UnboundLocalError führt.[2]

Wenn counter eine globale Variable ist, hilft das Schlüsselwort global . Wenn increment() eine lokale Funktion und counter eine lokale Variable ist, können Sie nonlocal in Python 3.x.

148
Sven Marnach

Sie müssen die globale Anweisung verwenden, damit Sie den globalen Variablenzähler anstelle einer lokalen Variablen ändern:

counter = 0

def increment():
  global counter
  counter += 1

increment()

Wenn der umschließende Bereich, in dem counter definiert ist, nicht der globale Bereich ist, können Sie auf Python 3.x die nicht-lokale Anweisung verwenden Dieselbe Situation auf Python 2.x Sie hätten keine Möglichkeit, den nicht-lokalen Namen counter neu zuzuweisen, also müssten Sie counter veränderbar machen und ändern :

counter = [0]

def increment():
  counter[0] += 1

increment()
print counter[0]  # prints '1'
78
Andrew Clark

Um die Frage in Ihrer Betreffzeile zu beantworten, * yes, gibt es in Python Abschlüsse, die jedoch nur innerhalb einer Funktion gelten, und (in Python 2.x) sind sie schreibgeschützt; Sie können den Namen nicht erneut an ein anderes Objekt binden (wenn das Objekt veränderbar ist, können Sie seinen Inhalt ändern.) In Python 3.x, können Sie das nonlocal Schlüsselwort zum Ändern einer Abschlussvariablen.

def incrementer():
    counter = 0
    def increment():
        nonlocal counter
        counter += 1
        return counter
    return increment

increment = incrementer()

increment()   # 1
increment()   # 2

* Der Titel der ursprünglichen Frage bezog sich auf Schließungen in Python.

16
kindall

Der Grund, warum Ihr Code ein UnboundLocalError auslöst, ist bereits in anderen Antworten gut erklärt.

Aber es scheint mir, dass Sie versuchen, etwas zu erstellen, das wie folgt funktioniert: itertools.count() .

Warum probierst du es nicht aus und siehst, ob es zu deinem Fall passt:

>>> from itertools import count
>>> counter = count(0)
>>> counter
count(0)
>>> next(counter)
0
>>> counter
count(1)
>>> next(counter)
1
>>> counter
count(2)
7
Rik Poggi

Python hat standardmäßig einen lexikalischen Gültigkeitsbereich. Dies bedeutet, dass ein eingeschlossener Gültigkeitsbereich zwar auf Werte in seinem umschließenden Gültigkeitsbereich zugreifen kann, diese jedoch nicht ändern kann (es sei denn, sie werden mit dem Schlüsselwort global als global deklariert.) .

Ein Abschluss bindet Werte in der einschließenden Umgebung an Namen in der lokalen Umgebung . Die lokale Umgebung kann dann den gebundenen Wert verwenden und diesen Namen sogar einem anderen Element zuweisen, die Bindung in der umschließenden Umgebung kann jedoch nicht geändert werden.

In Ihrem Fall versuchen Sie, counter als lokale Variable und nicht als gebundenen Wert zu behandeln. Beachten Sie, dass dieser Code, der den in der umgebenden Umgebung zugewiesenen Wert von x bindet, einwandfrei funktioniert:

>>> x = 1

>>> def f():
>>>  return x

>>> f()
1
4
Chris Taylor

Um eine globale Variable innerhalb einer Funktion zu ändern, müssen Sie das Schlüsselwort global verwenden.

Wenn Sie versuchen, dies ohne die Linie zu tun

global counter

innerhalb der Definition von Inkrement wird eine lokale Variable mit dem Namen counter erstellt, um zu verhindern, dass Sie die Zählervariable durcheinander bringen, von der das gesamte Programm abhängig sein kann.

Beachten Sie, dass Sie global nur verwenden müssen, wenn Sie die Variable ändern. Sie können den Zähler inkrementell ablesen, ohne die globale Anweisung zu benötigen.

3
chucksmash

versuche dies

counter = 0

def increment():
  global counter
  counter += 1

increment()
2
Lostsoul
0
Marcin