Die Zuweisung einer Variablen (z.B. a = b) in Python kopiert nicht das Objekt selbst, sondern erstellt nur einen neuen Namen (Verweis) auf das bestehende Objekt. Änderungen über einen Namen sind auch über den anderen sichtbar, wenn es sich um ein veränderbares Objekt handelt.
Shallow copy (flaches Kopieren), z.B. über copy.copy(obj) oder mit einem Slice [:] für Listen, erstellt ein neues Objekt auf oberster Ebene, aber die darin enthaltenen Objekte werden per Referenz kopiert (d.h. beide Strukturen "zeigen" auf die gleichen Untercontainer). Wenn die inneren Objekte geändert werden, sind die Änderungen durch beide Objekte sichtbar.
Beispiel:
import copy lst1 = [[1,2], [3,4]] lst2 = copy.copy(lst1) # oder lst1[:] lst1[0][0] = 100 print(lst2) # [[100, 2], [3, 4]]
lst2 ist eine neue Liste, aber ihr erstes Element ist dieselbe verschachtelte Liste.
Frage: Was ist der Unterschied zwischen lst2 = lst1[:] und lst2 = copy.copy(lst1)?
Antwort: In der Praxis gibt es für gewöhnliche (einzelne) Listen keine Unterschiede – beide Methoden erstellen eine flache Kopie der Liste. Für benutzerdefinierte Containerklassen kann jedoch ein unterschiedliches Verhalten auftreten (z.B. wenn die Methode __copy__ implementiert wurde). Ebenso ist es sicherer, für andere Typen (dict, set usw.) das spezialisierte Modul copy zu verwenden.
import copy lst1 = [1, 2, 3] lst2 = lst1[:] lst3 = copy.copy(lst1) print(lst2 == lst3) # True
Geschichte
In einem Projekt zur Verarbeitung von Konfigurationen duplizierte der Entwickler die Standardparameter durch Zuweisung params = default_params und stellte sich vor, dass er sie "isoliert" ändern könnte. Infolgedessen führten Änderungen in einer Kopie zu einem Kaskadeneffekt in allen Teilen der Anwendung, weil sie tatsächlich mit demselben Objekt arbeiteten.
Geschichte
Ein unerfahrener Programmierer verwendete eine flache Kopie der Liste zur Speicherung des Spielstands (game_states = states[:]). Bei einer verschachtelten Struktur (Listen von Figuren auf dem Feld) „übertrugen“ sich Änderungen innerhalb eines Zustands in andere, was die Geschichte der Rücksetzungen und Wiederholungen der Züge zerstörte.
Geschichte
Bei dem Versuch, Daten in einer OOP-Anwendung zu klonen, gab es die Wahl zwischen einem Slice und copy.copy(). Aber in der Struktur gab es eine eigene Klasse mit ihrer eigenen Kopiermethode, die nur bei der Verwendung von copy.copy() berücksichtigt wurde. Der Slice ignorierte die Logik der Objekterstellung, und es traten unerwartete Bugs auf.