Python: LOAD_FAST vs. LOAD_DEREF mit Inplace-Zusatz

Letzten Freitag ging ich zu einem Vorstellungsgespräch und musste die folgende Frage beantworten: Warum löst dieser Code eine Ausnahme aus UnboundLocalError: local variable 'var' referenced before assignment in der Zeile mitvar += 1)?

def outer():
    var = 1

    def inner():
        var += 1
        return var

    return inner

Ich konnte keine richtige Antwort geben; Diese Tatsache hat mich sehr verärgert, und als ich nach Hause kam, habe ich mich sehr bemüht, eine richtige Antwort zu finden. Nun, ichhabe fand die Antwort, aber jetzt gibt es noch etwas, das mich verwirrt.

Ich muss im Voraus @ sag dass meine Frage eher die Entscheidungen betrifft, die beim Entwerfen der Sprache getroffen wurden, als die Funktionsweise.

Also, betrachten Sie diesen Code. Die innere Funktion ist ein Python-Verschluss undvar ist nicht lokal fürouter - es wird in einer Zelle gespeichert (und dann aus einer Zelle abgerufen):

def outer():
    var = 1

    def inner():
        return var

    return inner

Die Demontage sieht folgendermaßen aus:

0  LOAD_CONST               1 (1)
3  STORE_DEREF              0 (var)  # not STORE_FAST

6  LOAD_CLOSURE             0 (var)
9  BUILD_TUPLE              1
12 LOAD_CONST               2 (<code object inner at 0x10796c810)
15 LOAD_CONST               3 ('outer.<locals>.inner')
18 MAKE_CLOSURE             0
21 STORE_FAST               0 (inner)

24 LOAD_FAST                0 (inner)
27 RETURN_VALUE

recursing into <code object inner at 0x10796c810:

0  LOAD_DEREF               0 (var)  # same thing
3  RETURN_VALUE

Dies ändert sich, wenn wir versuchen, etwas anderes an @ zu bindevar innerhalb der inneren Funktion:

def outer():
    var = 1

    def inner():
        var = 2
        return var

    return inner

ochmals die Demontage:

0  LOAD_CONST               1 (1)
3  STORE_FAST               0 (var)  # this one changed
6  LOAD_CONST               2 (<code object inner at 0x1084a1810)
9  LOAD_CONST               3 ('outer.<locals>.inner')
12 MAKE_FUNCTION            0  # AND not MAKE_CLOSURE
15 STORE_FAST               1 (inner)

18 LOAD_FAST                1 (inner)
21 RETURN_VALUE

recursing into <code object inner at 0x1084a1810:

0  LOAD_CONST               1 (2)
3  STORE_FAST               0 (var)  # 'var' is supposed to be local

6  LOAD_FAST                0 (var)  
9  RETURN_VALUE

Wir speichernvar local, was den Angaben in der Dokumentation entspricht:Namenzuweisungen gehen immer in den innersten Bereich.

Nun, wenn wir versuchen, ein Inkrement zu machenvar += 1, eine böseLOAD_FAST erscheint, der versucht, @ zu bekommvar voninnerokaler Geltungsbereich von @:

14 LOAD_FAST                0 (var)
17 LOAD_CONST               2 (2)
20 INPLACE_ADD
21 STORE_FAST               0 (var)

Und natürlich bekommen wir einen Fehler. Jetzt,hier ist was ich nicht bekomme: warum können wir nicht abrufenvar mit einerLOAD_DEREF, und dann speichern Sie es ininner 's Umfang mit einemSTORE_FAST? Ich meine, das scheint OK zu sein. mit dem "innersten Bereich" Zuweisungsmaterial, und gleichzeitig ist es etwas intuitiver wünschenswert. Zumindest das+= code würde tun, was wir wollen, und ich kann mir keine Situation einfallen lassen, in der der beschriebene Ansatz etwas durcheinander bringen könnte.

Können Sie? Ich habe das Gefühl, dass mir hier etwas fehlt.

Antworten auf die Frage(6)

Ihre Antwort auf die Frage