Kann mir bitte jemand das erklären? Das ergibt für mich keinen Sinn.
Ich kopiere ein Wörterbuch in ein anderes und bearbeite das zweite und beide werden geändert. Warum passiert dies?
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}
python
python-3.x
dictionary
reference
MadSc13ntist
quelle
quelle
dict1
und daraufdict2
verweisen.Antworten:
Python kopiert niemals implizit Objekte. Wenn Sie festlegen
dict2 = dict1
, verweisen sie auf dasselbe exakte Diktierobjekt. Wenn Sie es also mutieren, beziehen sich alle Verweise darauf weiterhin auf das Objekt in seinem aktuellen Zustand.Wenn Sie das Diktat kopieren möchten (was selten vorkommt), müssen Sie dies explizit mit tun
oder
quelle
dir(1)
zu sehen), aber sie werden implizit kopiert.int
,float
Undbool
Instanzen sind echte Python - Objekte, und b) Objekte dieser Art wird nicht implizit kopiert , wenn Sie sie übergeben, nicht in einer semantischen Python - Ebene sicher und nicht einmal als Implementierungsdetail in CPython.copy.deepcopy()
stattdict()
oderdict.copy()
. Imran ‚s kurze Antwort ist auf der rechten Seite der Vernunft, im Gegensatz zu dieser Antwort.Wenn Sie zuweisen
dict2 = dict1
, erstellen Sie keine Kopie vondict1
, esdict2
ist nur ein anderer Name fürdict1
.Verwenden Sie
copy
/deepcopy
descopy
Moduls , um die veränderlichen Typen wie Wörterbücher zu kopieren .quelle
Während
dict.copy()
unddict(dict1)
generiert eine Kopie, sind sie nur flache Kopien. Wenn Sie eine tiefe Kopie wünschen ,copy.deepcopy(dict1)
ist erforderlich. Ein Beispiel:In Bezug auf flache und tiefe Kopien aus den Dokumenten des Python-
copy
Moduls :quelle
w=copy.deepcopy(x)
ist die Schlüsselzeile.dict2 = dict1
unddict2 = copy.deepcopy(dict1)
?Unter Python 3.5+ gibt es eine einfachere Möglichkeit, eine flache Kopie mit dem Operator ** Unpackaging zu erstellen. Definiert durch Pep 448 .
** entpackt das Wörterbuch in ein neues Wörterbuch, das dann dict2 zugewiesen wird.
Wir können auch bestätigen, dass jedes Wörterbuch eine eigene ID hat.
Wenn eine tiefe Kopie benötigt wird, ist copy.deepcopy () immer noch der richtige Weg.
quelle
dict2 = {**dict1, 'key3':'value3'}
Die besten und einfachsten Möglichkeiten , eine Kopie eines Diktats in Python 2.7 und 3 zu erstellen, sind ...
So erstellen Sie eine Kopie eines einfachen (einstufigen) Wörterbuchs:
1. Verwenden Sie die dict () -Methode, anstatt eine Referenz zu generieren, die auf das vorhandene dict verweist.
2. Verwenden der integrierten update () -Methode des Python-Wörterbuchs.
So erstellen Sie eine Kopie eines verschachtelten oder komplexen Wörterbuchs:
Verwenden Sie die integrierte in Kopie - Modul, das eine generische flache und tiefe Kopiervorgänge zur Verfügung stellt. Dieses Modul ist sowohl in Python 2.7 als auch in Python 3 vorhanden. *
quelle
dict()
entsteht eine flache Kopie, keine tiefe Kopie. Das heißt, wenn Sie ein verschachteltes haben,dict
ist das äußeredict
eine Kopie, aber das innere Diktat ist ein Verweis auf das ursprüngliche innere Diktat.Sie können auch einfach ein neues Wörterbuch mit einem Wörterbuchverständnis erstellen. Dadurch wird das Importieren von Kopien vermieden.
Natürlich können Sie in Python> = 2.7 Folgendes tun:
Für die Abwärtskompatibilität ist die Top-Methode jedoch besser.
quelle
d2 = dict.copy(d1)
auch keine Importe erforderlich.d2 = d1.copy()
dict.items
gibt bereits ein iterierbares Schlüssel / Wert-Paar zurück. Sie können also einfach verwendendict(mydict.items())
(Sie können auch nur verwendendict(mydict)
). Es kann nützlich sein, das Verständnis zu haben, wenn Sie die Einträge filtern möchten.Zusätzlich zu den anderen bereitgestellten Lösungen können Sie
**
das Wörterbuch in ein leeres Wörterbuch integrieren, z.shallow_copy_of_other_dict = {**other_dict}
.Jetzt haben Sie eine "flache" Kopie von
other_dict
.Auf Ihr Beispiel angewendet:
Zeiger: Unterschied zwischen flachen und tiefen Kopien
quelle
Zuweisungsanweisungen in Python kopieren keine Objekte, sondern erstellen Bindungen zwischen einem Ziel und einem Objekt.
So
dict2 = dict1
ergibt sich eine weitere Bindung zwischendict2
und das Objekt , dasdict1
Bezug zu nehmen.Wenn Sie ein Diktat kopieren möchten, können Sie das verwenden
copy module
. Das Kopiermodul hat zwei Schnittstellen:Der Unterschied zwischen flachem und tiefem Kopieren ist nur für zusammengesetzte Objekte relevant (Objekte, die andere Objekte enthalten, wie Listen oder Klasseninstanzen):
Eine flache Kopie erstellt ein neues zusammengesetztes Objekt und fügt dann (soweit möglich) Verweise auf die im Original gefundenen Objekte ein.
Eine tiefe Kopie erstellt ein neues zusammengesetztes Objekt und fügt dann rekursiv Kopien der im Original gefundenen Objekte ein.
Zum Beispiel in Python 2.7.9:
und das Ergebnis ist:
quelle
Sie können die neu erstellte Kopie auf einmal kopieren und bearbeiten, indem Sie den
dict
Konstruktor mit zusätzlichen Schlüsselwortargumenten aufrufen :quelle
Das verwirrte mich anfangs auch, weil ich aus einem C-Hintergrund stammte.
In C ist eine Variable ein Speicherort mit einem definierten Typ. Durch Zuweisen zu einer Variablen werden die Daten in den Speicherort der Variablen kopiert.
In Python verhalten sich Variablen jedoch eher wie Zeiger auf Objekte. Wenn Sie also eine Variable einer anderen zuweisen, wird keine Kopie erstellt, sondern der Variablenname verweist nur auf dasselbe Objekt.
quelle
Jede Variable in Python (Dinge wie
dict1
oderstr
oder__builtins__
ist ein Zeiger auf ein verstecktes platonisches "Objekt" in der Maschine.Wenn Sie festlegen
dict1 = dict2
, zeigen Sie einfachdict1
auf dasselbe Objekt (oder denselben Speicherort oder eine beliebige Analogie) wiedict2
. Das Objekt, auf das verwiesen wird,dict1
ist dasselbe Objekt, auf das verwiesen wirddict2
.Sie können überprüfen:
dict1 is dict2
sollte seinTrue
. Auchid(dict1)
sollte das gleiche sein wieid(dict2)
.Du willst
dict1 = copy(dict2)
oderdict1 = deepcopy(dict2)
.Der Unterschied zwischen
copy
unddeepcopy
?deepcopy
wird sicherstellen, dass die Elemente vondict2
(haben Sie es auf eine Liste gezeigt?) auch Kopien sind.Ich benutze nicht
deepcopy
viel - es ist normalerweise eine schlechte Praxis, Code zu schreiben, der ihn benötigt (meiner Meinung nach).quelle
dict1
ist ein Symbol, das auf ein zugrunde liegendes Wörterbuchobjekt verweist. Durch Zuweisendict1
zu wirddict2
lediglich dieselbe Referenz zugewiesen . Durch Ändern des Werts eines Schlüssels über dasdict2
Symbol wird das zugrunde liegende Objekt geändert, was sich auch auswirktdict1
. Das ist verwirrend.Es ist weitaus einfacher, über unveränderliche Werte als über Referenzen nachzudenken. Erstellen Sie daher nach Möglichkeit Kopien:
Dies ist syntaktisch dasselbe wie:
quelle
dict2 = dict1
kopiert das Wörterbuch nicht. Es gibt dem Programmierer einfach eine zweite Möglichkeit (dict2
), auf dasselbe Wörterbuch zu verweisen.quelle
Es gibt viele Möglichkeiten, ein Dict-Objekt zu kopieren, das ich einfach benutze
quelle
dict_2 = dict_1.copy()
ist viel effizienter und logischer.Wie andere erklärt haben, macht das eingebaute
dict
nicht das, was Sie wollen. In Python2 (und wahrscheinlich auch in 3) können Sie problemlos eineValueDict
Klasse erstellen , mit der kopiert wird,=
sodass Sie sicher sein können, dass sich das Original nicht ändert.Bitte beziehen Sie sich auf das hier beschriebene lvalue-Änderungsmuster: Python 2.7 - saubere Syntax für die lvalue-Änderung . Die wichtigste Beobachtung ist, dass
str
undint
sich in Python als Werte verhalten (obwohl es sich tatsächlich um unveränderliche Objekte unter der Haube handelt). Während Sie das beobachten, beachten Sie bitte auch, dass nichts magisch Besonderes anstr
oder istint
.dict
kann auf die gleiche Weise verwendet werden, und ich kann mir viele Fälle vorstellen, in denenValueDict
Sinn macht.quelle
Der folgende Code befindet sich in Diktaten, die der JSON-Syntax mehr als dreimal schneller folgen als Deepcopy
quelle
Ich stieß auf ein eigenartiges Verhalten, als ich versuchte, die Wörterbuch-Eigenschaft der Klasse zu kopieren, ohne sie einer Variablen zuzuweisen
new = copy.deepcopy(my_class.a)
funktioniert nicht dh modifizierennew
modifiziertmy_class.a
aber wenn Sie dies tun
old = my_class.a
und dannnew = copy.deepcopy(old)
funktioniert es perfekt, dh das Ändernnew
wirkt sich nicht ausmy_class.a
Ich bin mir nicht sicher, warum dies passiert, hoffe aber, dass es hilft, einige Stunden zu sparen! :) :)
quelle
my_class.a
?weil dict2 = dict1 ist, enthält dict2 den Verweis auf dict1. Sowohl dict1 als auch dict2 zeigen auf dieselbe Stelle im Speicher. Dies ist nur ein normaler Fall, wenn Sie mit veränderlichen Objekten in Python arbeiten. Wenn Sie mit veränderlichen Objekten in Python arbeiten, müssen Sie vorsichtig sein, da das Debuggen schwierig ist. Wie das folgende Beispiel.
In diesem Beispiel sollen alle Benutzer-IDs einschließlich blockierter IDs abgerufen werden. Das haben wir von der Variablen ids bekommen, aber wir haben auch den Wert von my_users unbeabsichtigt aktualisiert . Wenn Sie die IDs mit blockierten_IDs erweitert haben, wurden my_users aktualisiert, da sich die IDs auf my_users beziehen .
quelle
Kopieren mit einer for-Schleife:
quelle
deepcopy
, das ausdrücklich für diesen Zweck gebaut wurde?Sie können direkt verwenden:
Dabei ist das Objekt dict2 eine unabhängige Kopie von dict1, sodass Sie dict2 ändern können, ohne dict1 zu beeinflussen.
Dies funktioniert für jede Art von Objekt.
quelle
__repr__
die durch eval rekonstruiert werden kann, und die Klasse des Objekts befindet sich möglicherweise nicht in dem aktuell aufzurufenden Bereich. Selbst wenn Sie sich an integrierte Typen halten, schlägt dies fehl, wenn dasselbe Objekt unter mehreren Schlüsseln gespeichert wird, dadict2
dann zwei separate Objekte vorhanden wären. Ein selbstreferenzielles Wörterbuch, in dem es sichdict1
selbst enthält, enthält stattdessenEllipsis
. Es wäre besser zu verwendendict1.copy()