Warum funktioniert das?
%Vor%aber das nicht:
%Vor%Ich bekomme diesen Fehler:
%Vor%Der Fehler scheint das Wurzelproblem nicht sehr anschaulich zu machen. Mike erklärt die Nachrichten, aber das erklärt nicht die Ursache.
Das eigentliche Problem ist, dass Sie in Python keine geschlossenen Variablen zuweisen können. In Funktion2 ist 'a' also nur lesbar. Wenn Sie ihm zuweisen, erstellen Sie eine neue Variable, die, wie Mike hervorhebt, Sie lesen, bevor Sie schreiben.
Wenn Sie der äußeren Variable aus dem inneren Bereich zuweisen möchten, müssen Sie wie folgt schummeln:
%Vor%So al ist unveränderlich, aber sein Inhalt ist nicht und Sie können sie ändern, ohne eine neue Variable zu erstellen.
Es sollte angemerkt werden, dass dies ein Syntaxfehler in Python ist. Python selbst (auf der Bytecode-Ebene) kann diesen Variablen gut zuweisen; Es gibt einfach keine Syntax in 2.x, um anzuzeigen, dass Sie dies tun möchten. Es geht davon aus, dass wenn Sie einer Variablen in einer Verschachtelungsebene zuweisen, dies bedeutet, dass es sich um eine lokale Verschachtelung handelt.
Das ist ein großer Mangel; in der Lage zu sein, Schließungen zuzuordnen, ist grundlegend. Ich habe das mehrfach mit Charliebs Hack bearbeitet.
Python 3 behebt dies mit dem sehr ungeschickten "nonlocal" Schlüsselwort:
%Vor%Es ist sehr dürftig, dass diese Syntax nur in 3.x verfügbar ist; Die meisten Leute stecken in 2.x fest und müssen weiterhin Hacks verwenden, um dieses Problem zu umgehen. Dies muss dringend nach 2.x zurückportiert werden.
Im nicht funktionierenden Snippet weisen Sie a
zu, wenn Sie " a -= 1
" sagen. Daher ist function2
, a
lokal für diesen Bereich und nicht der umschließende Bereich. Pythons Closures sind lexikalisch - es sucht nicht dynamisch nach a
im Rahmen von function2
und wenn es nicht zugewiesen wurde, geh und suche es im Rahmen von function1
.
Beachten Sie, dass dies nicht von der Rekursivität oder der Verwendung von Closures abhängt. Betrachten Sie das Beispiel dieser Funktion
%Vor% Wenn Sie es aufrufen, erhalten Sie auch UnboundLocalError
. (Ohne a = 4
würde entweder das globale a
verwendet oder, wenn es keines gibt, ein NameError
.) Da a
möglicherweise innerhalb dieses Bereichs zugewiesen ist, ist es lokal.
Wenn ich diese Funktion entwerfe, könnte ich einen Ansatz verwenden, der eher wie
aussieht %Vor% (oder natürlich for a in xrange(10, -1, -1): print a
;-))