Ich versuche, Pythons Ansatz für den variablen Bereich zu verstehen. Warum kann in diesem Beispiel f()
der Wert von x
, wie in ihm wahrgenommen main()
, aber nicht der Wert von n
geändert werden?
def f(n, x):
n = 2
x.append(4)
print('In f():', n, x)
def main():
n = 1
x = [0,1,2,3]
print('Before:', n, x)
f(n, x)
print('After: ', n, x)
main()
Ausgabe:
Before: 1 [0, 1, 2, 3]
In f(): 2 [0, 1, 2, 3, 4]
After: 1 [0, 1, 2, 3, 4]
Antworten:
Einige Antworten enthalten das Wort "Kopie" in einem Kontext eines Funktionsaufrufs. Ich finde es verwirrend.
Python kopiert niemals Objekte, die Sie während eines Funktionsaufrufs übergeben .
Funktionsparameter sind Namen . Wenn Sie eine Funktion aufrufen, bindet Python diese Parameter an alle Objekte, die Sie übergeben (über Namen in einem Aufruferbereich).
Objekte können veränderlich (wie Listen) oder unveränderlich (wie Ganzzahlen, Zeichenfolgen in Python) sein. Veränderbares Objekt, das Sie ändern können. Sie können einen Namen nicht ändern, sondern nur an ein anderes Objekt binden.
In Ihrem Beispiel geht es nicht um Bereiche oder Namespaces , sondern um das Benennen und Binden sowie die Veränderbarkeit eines Objekts in Python.
Hier sind schöne Bilder zum Unterschied zwischen Variablen in anderen Sprachen und Namen in Python .
quelle
def foo(x, l=None): l=l or []; l.append(x**2); return l[-1]
.x = []
inf()
hat keine Auswirkung auf die Listex
in der Hauptfunktion. Ich habe den Kommentar aktualisiert, um ihn genauer zu gestalten.Sie haben bereits eine Reihe von Antworten, und ich stimme JF Sebastian weitgehend zu, aber Sie finden dies möglicherweise als Abkürzung nützlich:
Jedes Mal
varname =
, wenn Sie sehen , erstellen Sie eine neue Namensbindung im Funktionsumfang. Welcher Wert zuvorvarname
gebunden war, geht in diesem Bereich verloren .Jedes Mal, wenn Sie sehen, dass
varname.foo()
Sie eine Methode aufrufenvarname
. Die Methode kann den Variablennamen ändern (zlist.append
. B. ).varname
(oder vielmehr das Objekt, das benannt wirdvarname
) kann in mehr als einem Bereich vorhanden sein, und da es sich um dasselbe Objekt handelt, sind alle Änderungen in allen Bereichen sichtbar.[Beachten Sie, dass das
global
Schlüsselwort eine Ausnahme zum ersten Fall erstellt]quelle
f
ändert den Wert von nicht wirklichx
(was immer der gleiche Verweis auf eine Instanz einer Liste ist). Vielmehr ändert es den Inhalt dieser Liste.In beiden Fällen wird eine Kopie einer Referenz an die Funktion übergeben. Innerhalb der Funktion,
n
wird ein neuer Wert zugewiesen. Nur die Referenz innerhalb der Funktion wird geändert, nicht die außerhalb.x
wird kein neuer Wert zugewiesen: Weder die Referenz innerhalb noch außerhalb der Funktion wird geändert. Stattdessen wirdx
der Wert von geändert.Da sich sowohl die
x
Innenseite als auch die Außenseite auf denselben Wert beziehen, sehen beide die Änderung. Im Gegensatzn
dazu beziehen sich das Innere der Funktion und das Äußere auf unterschiedliche Werte, nachdemn
sie innerhalb der Funktion neu zugewiesen wurden.quelle
Ich werde Variablen umbenennen, um Verwirrung zu vermeiden. n -> nf oder nmain . x -> xf oder xmain :
Wenn Sie die Funktion f aufrufen , erstellt die Python-Laufzeit eine Kopie von xmain und weist sie xf zu . In ähnlicher Weise weist sie nf eine Kopie von nmain zu .
Im Fall von n ist der kopierte Wert 1.
Im Fall von x ist der kopierte Wert nicht die Literalliste [0, 1, 2, 3] . Es ist ein Verweis auf diese Liste. xf und xmain zeigen auf dieselbe Liste. Wenn Sie also xf ändern, ändern Sie auch xmain .
Wenn Sie jedoch etwas schreiben würden wie:
Sie würden feststellen, dass sich xmain nicht geändert hat. Dies liegt daran, dass Sie in der Zeile xf = ["foo", "bar"] xf so geändert haben, dass es auf eine neue Liste verweist . Alle Änderungen, die Sie an dieser neuen Liste vornehmen, haben keine Auswirkungen auf die Liste, auf die xmain noch verweist.
Hoffentlich hilft das. :-)
quelle
nf = 2
der Namenf
geändert wird, um auf zu zeigen2
. Zahlen sind unveränderlich, Listen sind veränderlich.Das liegt daran, dass eine Liste ein veränderbares Objekt ist. Sie setzen x nicht auf den Wert [0,1,2,3], sondern definieren eine Beschriftung für das Objekt [0,1,2,3].
Sie sollten Ihre Funktion f () folgendermaßen deklarieren:
quelle
x = x + [4]
stattdessen tun würdenx.append(4)
, würden Sie auch beim Anrufer keine Änderung sehen, obwohl eine Liste veränderbar ist. Es hat damit zu tun, ob es tatsächlich mutiert ist.x += [4]
dannx
mutiert ist, so wie das, was mit geschiehtx.append(4)
, so wird der Anrufer die Änderung sehen.n ist ein int (unveränderlich), und eine Kopie wird an die Funktion übergeben. In der Funktion ändern Sie also die Kopie.
X ist eine Liste (veränderbar), und eine Kopie des Zeigers wird an die Funktion übergeben, sodass x.append (4) den Inhalt der Liste ändert. Wenn Sie jedoch in Ihrer Funktion x = [0,1,2,3,4] gesagt haben, würden Sie den Inhalt von x in main () nicht ändern.
quelle
Wenn die Funktionen mit völlig unterschiedlichen Variablen neu geschrieben werden und wir sie mit id aufrufen , wird der Punkt gut veranschaulicht. Ich habe das zuerst nicht verstanden und den Beitrag von jfs mit der großartigen Erklärung gelesen , also habe ich versucht, mich selbst zu verstehen / zu überzeugen:
z und x haben die gleiche ID. Nur verschiedene Tags für dieselbe zugrunde liegende Struktur wie im Artikel angegeben.
quelle
Python ist eine reine Pass-by-Value-Sprache, wenn Sie richtig darüber nachdenken. Eine Python-Variable speichert den Speicherort eines Objekts im Speicher. Die Python-Variable speichert das Objekt selbst nicht. Wenn Sie eine Variable an eine Funktion übergeben, übergeben Sie eine Kopie der Adresse des Objekts, auf das die Variable zeigt.
Vergleichen Sie diese beiden Funktionen
Nun, wenn Sie in die Shell eingeben
Vergleichen Sie dies mit goo.
Im ersten Fall übergeben wir eine Kopie der Adresse der Kuh an foo und foo hat den Status des dort befindlichen Objekts geändert. Das Objekt wird geändert.
Im zweiten Fall übergeben Sie eine Kopie der Adresse der Kuh an goo. Dann ändert goo diese Kopie. Wirkung: keine.
Ich nenne das das Prinzip des rosa Hauses . Wenn Sie eine Kopie Ihrer Adresse erstellen und einem Maler sagen, dass er das Haus an dieser Adresse rosa streichen soll, erhalten Sie ein rosa Haus. Wenn Sie dem Maler eine Kopie Ihrer Adresse geben und ihn auffordern, diese in eine neue Adresse umzuwandeln, ändert sich die Adresse Ihres Hauses nicht.
Die Erklärung beseitigt viel Verwirrung. Python übergibt die Adressvariablen, die nach Wert gespeichert sind.
quelle
Python wird nach Referenzwert kopiert. Ein Objekt belegt ein Feld im Speicher, und diesem Objekt ist eine Referenz zugeordnet, die jedoch selbst ein Feld im Speicher belegt. Und Name / Wert ist einer Referenz zugeordnet. In der Python-Funktion wird immer der Wert der Referenz kopiert, sodass in Ihrem Code n als neuer Name kopiert wird. Wenn Sie diesen zuweisen, hat es einen neuen Platz im Aufruferstapel. Für die Liste wurde der Name ebenfalls kopiert, bezieht sich jedoch auf denselben Speicher (da Sie der Liste niemals einen neuen Wert zuweisen). Das ist eine Magie in Python!
quelle
Mein allgemeines Verständnis ist, dass jede Objektvariable (wie z. B. eine Liste oder ein Diktat) durch ihre Funktionen geändert werden kann. Ich glaube, Sie können den Parameter nicht neu zuweisen, dh ihn innerhalb einer aufrufbaren Funktion als Referenz zuweisen.
Das stimmt mit vielen anderen Sprachen überein.
Führen Sie das folgende kurze Skript aus, um zu sehen, wie es funktioniert:
quelle
Ich hatte meine Antwort tonnenweise geändert und festgestellt, dass ich nichts zu sagen habe, Python hatte sich bereits erklärt.
Dieser Teufel ist nicht die Referenz / Wert / veränderlich oder nicht / Instanz, Namensraum oder Variable / Liste oder str, ES IST DER SYNTAX, GLEICHES ZEICHEN.
quelle