1267 Stimmen

Wie man ein Wörterbuch kopiert und nur die Kopie bearbeitet

Ich setze dict2 = dict1. Wenn ich dict2 bearbeite, ändert sich auch das Original dict1. Warum?

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2["key2"] = "WARUM?!"
>>> dict1
{'key2': 'WARUM?!', 'key1': 'value1'}

1227voto

Mike Graham Punkte 68846

Python kopiert Objekte niemals implizit. Wenn Sie dict2 = dict1 setzen, machen Sie sie zu Referenzen auf dasselbe genaue Dictionary-Objekt, sodass, wenn Sie es verändern, alle Verweise darauf auf das Objekt in seinem aktuellen Zustand verweisen.

Wenn Sie das Dictionary kopieren möchten (was selten vorkommt), müssen Sie dies explizit tun mit

dict2 = dict(dict1)

oder

dict2 = dict1.copy()

984voto

Imran Punkte 81131

Wenn Sie dict2 = dict1 zuweisen, erstellen Sie keine Kopie von dict1, sondern dict2 wird zu einem weiteren Namen für dict1.

Um die veränderbaren Typen wie Wörterbücher zu kopieren, verwenden Sie copy / deepcopy des copy-Moduls.

import copy

dict2 = copy.deepcopy(dict1)

263voto

gpanda Punkte 2872

Während dict.copy() und dict(dict1) eine Kopie erstellen, handelt es sich nur um flache Kopien. Wenn Sie eine tiefe Kopie wünschen, ist copy.deepcopy(dict1) erforderlich. Ein Beispiel:

>>> source = {'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> copy1 = x.copy()
>>> copy2 = dict(x)
>>> import copy
>>> copy3 = copy.deepcopy(x)
>>> source['a'] = 10  # Eine Änderung an Eigenschaften der ersten Ebene wirkt sich nicht auf Kopien aus
>>> source
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy3
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> source['b']['m'] = 40  # Eine Änderung an tiefen Eigenschaften WIRD die flache Kopie der Eigenschaft 'b.m' beeinflussen
>>> source
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy3  # Die Eigenschaft 'b.m' der tiefen Kopie bleibt unverändert
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}

In Bezug auf flache vs. tiefe Kopien, aus den Python copy Moduldokumenten:

Der Unterschied zwischen flachen und tiefen Kopien ist nur relevant für zusammengesetzte Objekte (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 darauf ein, die auf die Objekte im Original gefunden wurden.
  • Eine tiefe Kopie erstellt ein neues zusammengesetztes Objekt und fügt dann rekursiv Kopien davon ein, die auf die Objekte im Original gefunden wurden.

93voto

Vkreddy Punkte 1448

Im Detail und eine einfache Möglichkeit zu erinnern:

Immer wenn du dict2 = dict1 machst, bezieht sich dict2 auf dict1. Sowohl dict1 als auch dict2 zeigen auf denselben Speicherort im Speicher. Dies ist nur ein normaler Fall bei der Arbeit mit veränderlichen Objekten in Python. Wenn du mit veränderlichen Objekten in Python arbeitest, musst du vorsichtig sein, da es schwer zu debuggen ist.

Statt dict2 = dict1 zu verwenden, solltest du die Kopie (shallow copy)- und deepcopy-Methode aus dem copy-Modul von Python verwenden, um dict2 von dict1 zu trennen.

Der richtige Weg ist:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WARUM?"
>>> dict2
{'key1': 'value1', 'key2': 'WARUM?'}
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>> id(dict1)
140641178056312
>>> id(dict2)
140641176198960
>>> 

Wie du sehen kannst, ist die id von dict1 und dict2 unterschiedlich, was bedeutet, dass beide auf verschiedene Speicherorte im Speicher zeigen/referenzieren.

Diese Lösung funktioniert für Wörterbücher mit unveränderlichen Werten; dies ist nicht die richtige Lösung für solche mit veränderlichen Werten.

Zum Beispiel:

>>> import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': False}}
>>> id(dict1)
140641197660704
>>> id(dict2)
140641196407832
>>> id(dict1["key2"])
140641176198960
>>> id(dict2["key2"])
140641176198960

Du siehst, dass obwohl wir eine Kopie für dict1 angewendet haben, der Wert von mutable sowohl in dict2 als auch in dict1 auf false geändert ist, obwohl wir es nur in dict2 geändert haben. Dies liegt daran, dass wir den Wert eines veränderlichen Wörterbuchteils von dict1 geändert haben. Wenn wir eine Kopie auf ein Wörterbuch anwenden, wird nur eine Shallow Copy durchgeführt, was bedeutet, dass es alle unveränderlichen Werte in ein neues Wörterbuch kopiert und nicht die veränderlichen Werte, sondern auf sie verweist.

Die ultimative Lösung besteht darin, eine Deepcopy von dict1 durchzuführen, um ein vollständig neues Wörterbuch mit allen kopierten Werten zu erstellen, einschließlich veränderlicher Werte.

>>>import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = copy.deepcopy(dict1)
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> id(dict1)
140641196228824
>>> id(dict2)
140641197662072
>>> id(dict1["key2"])
140641178056312
>>> id(dict2["key2"])
140641197662000
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': True}}

Wie du sehen kannst, sind die IDs unterschiedlich, das bedeutet, dass dict2 komplett ein neues Wörterbuch mit allen Werten in dict1 ist.

Deepcopy muss verwendet werden, wenn du immer einen der veränderlichen Werte ändern möchtest, ohne das Originalwörterbuch zu beeinflussen. Andernfalls kannst du eine Shallow Copy verwenden. Deepcopy ist langsam, da es rekursiv arbeitet, um alle verschachtelten Werte im Originalwörterbuch zu kopieren, und benötigt auch zusätzlichen Speicher.

75voto

PabTorre Punkte 2656

Python 3.5+ bietet eine einfachere Möglichkeit, eine flache Kopie zu erstellen, indem der **-Operator verwendet wird. Definiert von Pep 448.

>>>dict1 = {"key1": "value1", "key2": "value2"}
>>>dict2 = {**dict1}
>>>print(dict2)
{'key1': 'value1', 'key2': 'value2'}
>>>dict2["key2"] = "WARUM?!"
>>>print(dict1)
{'key1': 'value1', 'key2': 'value2'}
>>>print(dict2)
{'key1': 'value1', 'key2': 'WARUM?!'}

** 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 eindeutige id hat.

>>>id(dict1)
 178192816

>>>id(dict2)
 178192600

Wenn eine tiefe Kopie benötigt wird, ist copy.deepcopy() immer noch der richtige Weg.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X