14 Tests, um den überraschend verwirrenden Umfang von Python zu verstehen

Einführung

Der variable Umfang und der Referenzierungsmechanismus von Python sind überraschend unintuitiv, und Anfänger können in die Falle tappen. Aber sobald Sie die Regeln gelernt haben, ist es nicht mehr so kompliziert. Hier sind einige Punkte, die Ihnen helfen, das zu verstehen.

Beantworten Sie für jede Frage ** was ausgegeben wird oder ob ein Fehler ausgegeben wird **. Die Ausführungsumgebung ist Python 3. Das schwierige (oder eher verrückte) Problem ist, dass die Überschrift rot </ font> ist.

Frage 1

x = 1

if True:
    x = 2

print(x)

Antworten

2

In Python bildet die if-Anweisung keinen Gültigkeitsbereich. Daher ist "x" in der "if" -Anweisung dieselbe Variable wie das äußere "x".

Problem 2

for i in range(10):
    x = i * 2

print(i, x)

Antworten

9 18

Wie das "if" bildet die "for" -Anweisung keinen Gültigkeitsbereich, sodass auf Schleifenvariablen und intern definierte Variablen nach der "for" -Anweisung zugegriffen werden kann.

Problem 3

ls = [x * 2 for x in range(10)]

print(x)

Antworten

(print(x)An dem Ort)
NameError: name 'x' is not defined

Wenn das Listenverständnis ausgeführt wird, wird ein neuer Bereich erstellt und dort werden Schleifenvariablen definiert. Daher kann auf "X" nicht über "print (x)" zugegriffen werden, das im äußeren Bereich vorhanden ist.

Problem 4

funs = []

for i in range(5):
    def f():
        print(i)
    funs.append(f)

for fun in funs:
    fun()

Antworten

4
4
4
4
4

Die äußere Variable "i" wird innerhalb der Funktion "f" referenziert, aber der Wert von "i" zum Zeitpunkt der Ausführung von "print (i)" wird verwendet ". Alle fünf "f" werden nach der "for" -Anweisung ausgeführt. An diesem Punkt ist "i" 4 ", sodass alle" 4 "ausgeben.

Das gleiche passiert mit der Listeneinschlussnotation.

Problem 5

x = 0

def f():
    x = 1

f()
print(x)

Antworten

0

Da der durch die Funktion f gebildete Block [^ block] eine ** Zuweisungsanweisung ** von x = 1 hat, wird im Rahmen dieses Blocks eine neue Variable von x erstellt. Das heißt, das oberste "x" wird nicht durch "f" modifiziert.

[^ block]: block ist ein Code, der einem Bereich entspricht. Für jeden Block wird ein Bereich gebildet. Es sind die Funktionen, Module (dh die oberste Ebene) und Klassendefinitionen, die die Blöcke bilden.

Problem 6

x = 0

def f():
    print(x)
    x = 1

f()

Antworten

(print(x)An dem Ort)
UnboundLocalError: local variable 'x' referenced before assignment

Ähnlich wie beim vorherigen Problem hat der durch die Funktion f gebildete Block eine ** Zuweisungsanweisung ** von x = 1, sodass der Gültigkeitsbereich vor der Ausführung des Blocks x vor ** ist. Eine Variable namens x wird erstellt. Wenn jedoch "print (x)" ausgeführt wird, ist "x" ungebunden, sodass eine Ausnahme ausgelöst wird.

Problem 7

x = 0

def f():
    x += 1

f()
print(x)

Antworten

(print(x)An dem Ort)
UnboundLocalError: local variable 'x' referenced before assignment

Da "+ =" auch als Zuweisungsanweisung betrachtet wird, wird die Variable "x" in dem durch "f" gebildeten Block wie im vorherigen Problem erstellt. Wenn jedoch "x + = 1" ausgeführt wird, existiert der Wert von "x" nicht, sodass eine Ausnahme ausgelöst wird.

Sie müssen "global" oder "nicht lokal" verwenden, um den Wert von Variablen im äußeren Bereich zu ändern.

Problem 8

x = 0

def f():
    if False:
        x = 1
    print(x)

f()

Antworten

(print(x)An dem Ort)
UnboundLocalError: local variable 'x' referenced before assignment

Da die "if" -Anweisung keinen Block bildet, gibt es eine Zuweisungsanweisung für "x" in dem durch "f" gebildeten Block wie im vorherigen Problem, und die Variable "x" wird erstellt. In der Realität wird jedoch kein Wert für "x" zugewiesen, sodass eine Ausnahme auftritt.

Problem 9 </ font>

x = 0

def f():
    del x

f()

Antworten

(An der Stelle von del x)
UnboundLocalError: local variable 'x' referenced before assignment

Tatsächlich bewirkt die Anweisung "del", dass Variablen im Block erstellt werden, genau wie die Zuweisungsanweisung. Daher wird die Variable "x" in dem durch "f" gebildeten Block erstellt, aber eine Ausnahme tritt auf, weil "del x" ausgeführt wird, ohne dass der Wert von "x" existiert.

Die effektive Syntax zum Erstellen von Variablen auf diese Weise ist die Zuweisungsanweisung, die "del" -Anweisung, die "for" -Anweisung, die Klassendefinition, die Funktionsdefinition, die "import" -Anweisung und das "as" von "with" und "außer".

Problem 10

x = 0

def f():
    def g():
        print(x)
    x = 1
    g()

f()

Antworten

1

Wenn "g" ausgeführt wird, wird "1" ausgegeben, weil "x" im äußeren Bereich ("f") existiert und der Wert "1" ist.

Problem 11 </ font>

x = 0

def f():
    x = 1
    del x
    def g():
        print(x)
    g()

f()

Antworten

(print(x)An dem Ort)
NameError: free variable 'x' referenced before assignment in enclosing scope

Selbst wenn "del x" ausgeführt wird, bleibt "x" im Bereich von "f" bestehen (nur der Wert verschwindet). Daher bezieht sich "x" in "g" auf "x", definiert durch "f". Da dieses "x" jedoch keinen Wert hat, tritt eine Ausnahme auf.

Aus dem gleichen Grund ergeben die folgenden beiden Codes das gleiche Ergebnis.

x = 0

def f():
    x = 1
    def g():
        print(x)
    del x
    g()

f()
x = 0

def f():
    def g():
        print(x)
    x = 1
    del x
    g()

f()

Problem 12 </ font>

x = 1

def f():
    x = 2
    try:
        raise Exception()
    except Exception as x:
        pass

    def g():
        print(x)
    g()

f()

Antworten

(print(x)An dem Ort)
NameError: free variable 'x' referenced before assignment in enclosing scope

Wenn eine Ausnahme in der Anweisung "try" auftritt und die Klausel "Ausnahme" ausgeführt wird, wird der durch "as" angegebene Wert wie in "del" ** gelöscht **. Wenn "g" ausgeführt wird, existiert "x" in "f", hat jedoch keinen Wert, sodass eine Ausnahme auftritt.

Wenn die Ausnahmeklausel nicht ausgeführt wird, wird die entsprechende Variable nicht gelöscht.

Problem 13

x = 1

class C:
    x = 2
    def f():
        print(x)
    f()

Antworten

1

Der Code in der Klassendefinition ist in Bezug auf den Bereich speziell, und auf die dort definierten Variablen (Klassenvariablen) kann nur von diesem Bereich aus zugegriffen werden, ** nicht direkt von den Funktionen (dh Methoden) in der Klassendefinition **.

Problem 14 </ font>

x = 0

def f():
    x = 1
    def g():
        print(eval("x"))
    g()

f()

Antworten

0

Dies ist ein Problem mit dem (nicht intuitiven) Verhalten der Funktion "eval". Die einzigen Variablen, auf die über den von der Funktion "eval" ausgeführten Code zugegriffen werden kann, sind tatsächlich ** "globale Variablen" und "Variablen, die in dem Block definiert sind, in dem" eval "ausgeführt wird **", sowie die zwischen ihnen definierten Variablen Ist unzugänglich. Im aktuellen Code sind die Variablen (außer dem eingebauten), auf die über den an die Funktion "eval" übergebenen Code zugegriffen werden kann, die Variablen (nicht einmal eine), die in "x" und "g" in der ersten Zeile definiert sind. Daher wird auf die oberste Ebene "x" verwiesen und "0" ausgegeben.

Die Funktion exec verhält sich genauso.

Referenz

Recommended Posts