Versuchen Sie, diese drei Probleme zu lösen, und überprüfen Sie die Antworten am Ende des Artikels.
Tipp : Probleme haben etwas gemeinsam. Wenn Sie also zum zweiten oder dritten Problem übergehen, wird das erste Problem für Sie einfacher.
Erste Aufgabe
Es gibt mehrere Variablen:
x = 1
y = 2
l = [x, y]
x += 5
a = [1]
b = [2]
s = [a, b]
a.append(5)
Was wird beim Drucken angezeigt
l
und s
?
Zweite Aufgabe
Definieren wir eine einfache Funktion:
def f(x, s=set()):
s.add(x)
print(s)
Was passiert, wenn Sie anrufen:
>>f(7)
>>f(6, {4, 5})
>>f(2)
Dritte Aufgabe
Wir definieren zwei einfache Funktionen:
def f():
l = [1]
def inner(x):
l.append(x)
return l
return inner
def g():
y = 1
def inner(x):
y += x
return y
return inner
Was bekommen wir nach der Ausführung dieser Befehle?
>>f_inner = f()
>>print(f_inner(2))
>>g_inner = g()
>>print(g_inner(2))
Wie sicher sind Sie in Ihren Antworten? Lassen Sie uns Ihren Fall überprüfen.
Lösung des ersten Problems
>>print(l)
[1, 2]
>>print(s)
[[1, 5], [2]]
Warum reagiert die zweite Liste auf eine Änderung an ihrem ersten Element
a.append(5)
, während die erste Liste dieselbe Änderung vollständig ignoriert x+=5
?
Lösung des zweiten Problems
Mal sehen was passiert:
>>f(7)
{7}
>>f(6, {4, 5})
{4, 5, 6}
>>f(2)
{2, 7}
Warten Sie, sollte nicht das letzte Ergebnis sein
{2}
?
Lösung des dritten Problems
Das Ergebnis wird folgendermaßen aussehen:
>>f_inner = f()
>>print(f_inner(2))
[1, 2]
>>g_inner = g()
>>print(g_inner(2))
UnboundLocalError: local variable ‘y’ referenced before assignment
Warum
g_inner(2)
hat sie nicht 3
? Warum erinnert f()
sich die innere Funktion an den äußeren Bereich, die innere Funktion g()
jedoch nicht? Sie sind fast identisch!
Erläuterung
Was ist, wenn ich Ihnen sage, dass all diese Beispiele für seltsames Verhalten mit dem Unterschied zwischen veränderlichen und unveränderlichen Objekten in Python zusammenhängen?
Veränderbare Objekte wie Listen, Mengen oder Wörterbücher können an Ort und Stelle geändert werden. Unveränderliche Objekte wie numerische Werte und Zeichenfolgenwerte sowie Tupel können nicht geändert werden. Ihre "Veränderung" führt zur Schaffung neuer Objekte.
Erklärung der ersten Aufgabe
x = 1
y = 2
l = [x, y]
x += 5
a = [1]
b = [2]
s = [a, b]
a.append(5)
>>print(l)
[1, 2]
>>print(s)
[[1, 5], [2]]
Da es
x
unveränderlich ist, x+=5
ändert die Operation das ursprüngliche Objekt nicht, sondern erstellt ein neues. Das erste Element der Liste bezieht sich jedoch weiterhin auf das ursprüngliche Objekt, sodass sich sein Wert nicht ändert.
weil Bei einem veränderlichen Objekt
a.append(5)
ändert der Befehl das ursprüngliche Objekt (anstatt ein neues zu erstellen), und die Liste s
"sieht" die Änderungen.
Erklärung der zweiten Aufgabe
def f(x, s=set()):
s.add(x)
print(s)
>>f(7)
{7}
>>f(6, {4, 5})
{4, 5, 6}
>>f(2)
{2, 7}
Mit den ersten beiden Ergebnissen ist alles klar: Der erste Wert wird
7
zu dem anfänglich leeren Satz hinzugefügt und es stellt sich heraus {7}
; dann wird der Wert 6
zum Satz addiert {4, 5}
und erhalten {4, 5, 6}
.
Und dann beginnen seltsame Dinge. Der Wert wird
2
nicht zur leeren Menge hinzugefügt, sondern zu {7}. Warum? Der Anfangswert des optionalen Parameters wird s
nur einmal ausgewertet: Beim ersten Aufruf wird s als leerer Satz initialisiert. Und da es änderbar ist, wird es nach dem Anruf f(7)
„an Ort und Stelle“ geändert. Der zweite Aufruf f(6, {4, 5})
wirkt sich nicht auf den Standardparameter aus: Er wird durch eine Menge ersetzt {4, 5}
, dh es handelt sich um {4, 5}
eine andere Variable. Der dritte Aufruf f(2)
verwendet dieselbe Variables
Dies wurde beim ersten Aufruf verwendet, wird jedoch nicht als leerer Satz neu initialisiert, sondern von seinem vorherigen Wert übernommen {7}
.
Daher sollten Sie keine veränderlichen Argumente als Standardargumente verwenden. In diesem Fall muss die Funktion geändert werden:
def f(x, s=None):
if s is None:
s = set()
s.add(x)
print(s)
Erklärung der dritten Aufgabe
def f():
l = [1]
def inner(x):
l.append(x)
return l
return inner
def g():
y = 1
def inner(x):
y += x
return y
return inner
>>f_inner = f()
>>print(f_inner(2))
[1, 2]
>>g_inner = g()
>>print(g_inner(2))
UnboundLocalError: local variable ‘y’ referenced before assignment
Hier geht es um Verschlüsse: Interne Funktionen erinnern sich daran, wie ihre externen Namespaces zum Zeitpunkt ihrer Definition ausgesehen haben. Oder zumindest sollten sie sich erinnern, aber die zweite Funktion macht die Poker-Oberfläche und verhält sich so, als hätte sie nichts von ihrem externen Namespace gehört.
Warum passiert dies? Bei der Ausführung
l.append(x)
ändert sich das veränderbare Objekt, das bei der Definition der Funktion erstellt wurde. Die Variable l
bezieht sich jedoch weiterhin auf die alte Speicheradresse. Der Versuch, eine unveränderliche Variable in der zweiten Funktion zu ändern, führt jedoch dazu, dass y += x
y auf eine andere Speicheradresse verweist: Das ursprüngliche y wird vergessen, was zu einem UnboundLocalError führt.
Fazit
Der Unterschied zwischen veränderlichen und unveränderlichen Objekten in Python ist sehr wichtig. Vermeiden Sie das in diesem Artikel beschriebene seltsame Verhalten. Besonders:
- .
- - .