Ich bin diese Woche auf einige Probleme gestoßen, und dann wurde mir klar, dass es immer noch vergessene Teile gibt, die noch überprüft werden müssen, wenn das Grundwissen eine Weile nicht gefestigt wurde. Ich werde es hier notieren, um es aufzuzeichnen
Zuvor
Beschreiben Sie zunächst kurz das aufgetretene Problem. Die Anforderung besteht darin, die Ergebnisse von 2 Drucken zu schreiben
Wie Wie Sie sehen, zeigt a auf ein Listenobjekt. In Python bedeutet eine solche Zuweisungsanweisung tatsächlich, dass a auf die Speicheradresse zeigt, an der sich die Liste befindet, was als Konzept ähnlich einem Zeiger betrachtet werden kann.
Und b, beachten Sie, dass es das a-Objekt in eine Liste einschließt und es mit 5 multipliziert, sodass b wie eine große Liste mit allen darin enthaltenen Elementen aussehen sollte a
Und wenn ein Nachher Das Objekt wird angehängt, die implizite Bedeutung ist, dass die Liste im Speicher geändert wurde und alle Objekte, die auf dieses Objekt verweisen, sich ändern.
Ich drucke die ID von a aus und drucke gleichzeitig Die ID des Elements a, das im Objekt b enthalten ist, sodass Sie sehen können, dass in der Liste b die ID jedes Elements mit a identisch ist
Wir können sehen dass die ID (Speicheradresse) von Objekt a 10892296 ist. Obwohl b a in eine neue Liste einschließt, verweist dieses Element immer noch auf das Objekt mit derselben Adresse. Dies kann durch die folgende Abbildung erklärt werden
Danach haben wir die Anhängeoperation für a durchgeführt. Da es sich bei der Liste um ein Variablenobjekt handelt, hat sich seine Speicheradresse nicht geändert. Für diese Adresse im Speicher werden jedoch alle referenzierten Objekte gemeinsam geändert
Dies führt zu einer Überprüfung des Python-Referenzmechanismus und des flachen Kopierens und des tiefen Kopierens
Pythons Referenzmechanismus
Referenzmechanismus Fall 1
Aus dem obigen Beispiel können wir sehen, dass Python Das Endergebnis ist, dass beide Objekte darauf verweisen der Inhalt desselben Bereichs im Speicher
Schauen wir uns also das folgende Beispiel an
B übergibt A und referenziert auch die ID 17446024 Der Inhalt der Adresse und die ID (Speicheradresse). ) der beiden sind genau gleich
Durch die Operation A A[0]=3 oder A[3].append(6) wird also der Inhalt dieses Speichers geändert (da die Liste ist Bei einem variablen Objekt ändert sich die Speicheradresse nicht, wir werden später darüber sprechen)
Dies ist der grundlegendste Referenzfall (außerdem, da A und B beide auf dieselbe Speicheradresse verweisen, also auf den Inhalt modifiziert durch B kann auch auf A reflektiert werden)
Referenzmechanismus Fall 2
Sehen wir uns einen anderen Fall an
Wenn man sich die Frage ansieht, scheint es, dass Element 2 durch die Liste selbst ersetzt wird. Das Ergebnis könnte A=[1,[1,2,3],3] sein
Aber das ist nicht der Fall! ! Sie können sehen, dass es unendlich viele verschachtelte
im roten Feld gibt. Warum ist das so?
Tatsächlich liegt es daran, dass A auf die Liste [1,2,3] zeigt. In diesem Beispiel zeigt nur das zweite Element von A auf das A-Objekt selbst, also ist es nur das zweite Element von A. Die Struktur hat sich geändert! Allerdings zeigt A immer noch auf dieses Objekt
Wir können durch Drucken der ID von A sehen, dass sich seine Ausrichtung nicht geändert hat! !
Sehen Sie, die Richtung von A hat sich nicht geändert
Wenn wir dann den endgültigen Ausgabeeffekt erzielen wollen, ist das der Fall [ 1, [1,2,3],3], wie sollen wir es bedienen?
Hier verwenden wir flache Kopie. Die Verwendung kann wie folgt sein:
Flache Kopie und tiefe Kopie
Flache Kopie
Lassen Sie uns nun über flaches Kopieren und tiefes Kopieren sprechen. Die obige Methode führt eigentlich nur flache Kopien durch, was bedeutet, dass sie das ursprünglich referenzierte Objekt kopiert, aber nicht mehr auf dieselbe Objektadresse verweist
Schauen Sie sich das folgende Beispiel an. B führt eine flache Kopie durch die Operation B = A[:] aus. Sie können sehen, dass nach der flachen Kopie die von A und B referenzierten Speicheradressen bereits unterschiedlich sind Die Referenzadressen der Elemente in A und B sind immer noch dieselben. Seien Sie also sehr vorsichtig! Es gibt einen Unterschied! ! !
Der Unterschied in den Referenzspeicheradressen von A und B bedeutet, dass die Operation, die Sie an B ausführen, keine Auswirkungen auf A hat.
Zusammenfassung der flachen Kopie:
Die flache Kopie kann also als Kopieren einer Referenz, des neuen Objekts und des Originals zusammengefasst werden. Die Referenzen zu den Objekten werden unterschieden, aber die Adressreferenzen der internen Elemente sind immer noch dieselben
Aber auch flaches Kopieren verursacht Probleme. Was ist das Problem? Dies ist der Fall, wenn eine Verschachtelung vorliegt. Wie Sie beispielsweise in der folgenden Situation sehen können, habe ich B eine flache Kopie von A zugewiesen, sodass die IDs (Speicheradressen) von A und B unterschiedlich sind.
Wenn ich also A[0]=8 ändere, ist B nicht betroffen, da A und B unabhängige Referenzen sind, es aber eine verschachtelte Liste in der Mitte gibt [4 ,5,6]
Wir können dies [4,5,6] so verstehen: A und B verweisen immer noch aufeinander, das heißt, für die zweiten Elemente von A und B verweisen sie immer noch auf dieselbe A-Speicheradresse.
Da int außerdem ein unveränderlicher Typ ist, ändert sich nach der Änderung von A[0] in 8 seine Referenzadresse! Es unterscheidet sich von der Referenz des Elements B[0].
Deep Copy
Wie kann man also mit einer solchen Situation umgehen? Sie müssen das Kopiermodul im Python-Modul verwenden
Das Kopiermodul hat zwei Funktionen
1: copy.copy (das Objekt, das Sie kopieren möchten): Dies ist eine flache Kopie und die vorherige Die Eigenschaften der [:]-Operation in der Liste sind dieselben
2: copy.deepcopy (das Objekt, das Sie kopieren möchten): Dies ist eine tiefe Kopie, mit der Ausnahme, dass eine neue erstellt wird Objekt genau wie die flache Kopie, und für interne Elemente werden neue Referenzen generiert, um sie unabhängig voneinander zu trennen.
Sehen Sie sich das Beispiel unten an Es wird gesagt, dass es völlig unabhängig ist. Unabhängig davon, ob Sie die unveränderlichen Elemente in A oder die verschachtelten veränderlichen Elemente in A ändern, hat das Ergebnis keinen Einfluss auf B.
Mein Verständnis ist: Eine tiefe Kopie kann als rekursive Kopie bezeichnet werden Kopieren Sie alle verschachtelten Variablenelemente und referenzieren Sie sie dann unabhängig voneinander.
Deep Copy-Zusammenfassung:
Der Effekt von Deep Copy ist der gleiche B. das der flachen Kopie. Zusätzlich zum Generieren einer neuen Referenz aus der Objektreferenz hilft es Ihnen, alle verschachtelten Elemente einzeln zu trennen.
Zeichnung 2 von mir selbst, um den Unterschied zwischen flacher Kopie und zu zeigen tiefes Kopieren
Es ist zu beachten, dass die Referenzadresse der unveränderlichen Elemente in der Liste zwar nach dem flachen Kopieren immer noch dieselbe ist, aber da es sich um unveränderliche Elemente handelt, wird die Referenz nach jeder Änderung eines unveränderlichen Elements geändert Die Adresse ist neu, ohne dass sich dies auf die ursprüngliche Referenzadresse auswirkt.
Zusammenfassung
So, los geht's, oberflächlich copy Und der Mechanismus des Deep Copy ist grundsätzlich verstanden.
Es gibt auch besondere Umstände, die erklärt werden müssen
Für unveränderliche Typen: int, str, tuple, float und andere Elemente gibt es keine Kopie, nachdem sie geändert wurden, die Referenzadresse wird direkt geändert, wie unten gezeigt
Wenn sich jedoch verschachtelte Variablentypen innerhalb des unveränderlichen Typs befinden, können Sie weiterhin Deep Copy
verwenden
Auch zur Erinnerung: Die am häufigsten verwendete Methode ist die direkte Zuweisung (oder direkte Übergabe von Referenzen), wie im folgenden Beispiel.
Er kombiniert a und b. Zwei variable Elemente zeigen auf eine Speicheradresse gleichzeitig, sodass sich jede Änderung auf a und b auswirkt
Schließlich
Variablentyp: list , set, dict
unveränderliche Typen: int, str, float, tuple
Methode für flaches Kopieren: [:], copy.copy(), Factory-Funktion verwenden (list/dir/set)
Tiefe Kopie Methode: copy.deepcopy()
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des flachen Kopier-, Deep-Copy- und Referenzmechanismus von Python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!