ProgrammierungPython-Entwickler (Middleware, Backend, Tests)

Wie implementiert man das Kopieren von Sammlungen in Python richtig, wann reicht copy() nicht aus und warum, und wann ist deepcopy erforderlich?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort.

Hintergrund: Das Kopieren von Objekten (insbesondere Sammlungen – Listen, Wörterbücher) ist in Python entscheidend: Eine einfache Zuweisung zu einer Variablen erstellt eine neue Referenz, kein Duplikat. Die speziellen Methoden copy() und deepcopy() wurden geschaffen, um unerwünschte "Nebenwirkungen" bei der gemeinsamen Nutzung von Strukturen zu vermeiden.

Problem: Bei der Arbeit mit verschachtelten Sammlungen (Liste von Listen, Wörterbuch innerhalb eines Wörterbuchs) reproduziert ein einfaches copy() nur den Container, jedoch keine inneren Elemente. Dies kann zu schwer fassbaren Bugs führen: Eine Änderung an einem verschachtelten Element spiegelt sich in allen "Kopien" wider.

Lösung: copy.copy() erstellt eine flache Kopie (shallow copy) – einen neuen Container auf der obersten Ebene, aber die inneren Objekte bleiben die gleichen. copy.deepcopy() kopiert rekursiv alle inneren Objekte.

Beispielcode:

import copy lst = [[1, 2], [3, 4]] shallow = copy.copy(lst) deep = copy.deepcopy(lst) lst[0][0] = 10 print(shallow) # [[10, 2], [3, 4]] — das innere Objekt hat sich geändert! print(deep) # [[1, 2], [3, 4]] — deepcopy hat den ursprünglichen Zustand beibehalten

Wichtige Merkmale:

  • Eine einfache Zuweisung kopiert nur die Referenz, kein Duplikat
  • .copy() (oder copy.copy()) kopiert den "äußeren" Container, aber nicht die inneren Objekte
  • .deepcopy() wird für vollständige Unabhängigkeit der Kopien verwendet

Trickfragen.

Reicht es manchmal aus, lst2 = lst[:] zum Kopieren einer Liste zu schreiben?

lst2 = lst[:] erstellt eine flache Kopie der Liste, aber die inneren Objekte (zum Beispiel Listen innerhalb der Liste) bleiben nach wie vor gleich. Für flache Listen ist das ausreichend; für verschachtelte Strukturen jedoch nicht.

Beispiel:

lst = [[1], [2]] lst2 = lst[:] lst[0][0] = 99 print(lst2) # [[99], [2]] — das innere Element hat sich in beiden "Kopien" geändert

Funktioniert die Methode .copy() bei allen Sammlungen gleich?

Nein. Zum Beispiel funktioniert dict.copy() als flaches Kopieren, list.copy() wurde erst mit Python 3.3 eingeführt, für set gibt es die Methode set.copy(). Bei Benutzerobjekten hängt die Unterstützung von .copy() von der implementierten Methode ab.


Kann man überall auf deepcopy verzichten? Ist das sicher und effizient?

Nein. deepcopy ist eine teure Operation: Sie kann Leistungsprobleme verursachen, insbesondere bei großen Strukturen und funktioniert nicht bei nicht kopierbaren/geschlossenen oder nicht standardmäßigen Objekten. Verwenden Sie deepcopy nur, wenn Sie wirklich eine vollständig unabhängige, rekursive Kopie benötigen.


Typische Fehler und Anti-Pattern

  • Verwendung von einfacher Zuweisung oder .copy() anstelle von deepcopy für verschachtelte Strukturen
  • Anwendung von deepcopy auf alle Objekte hintereinander (verlangsamt das Programm)
  • Versuch, Objekte zu kopieren, die das Kopieren nicht unterstützen (z. B. Dateien, Streams)

Beispiel aus dem Leben

Negativer Fall

In Tests wurde das Kopieren eines "Wörterbuchs von Wörterbüchern" über dict.copy() durchgeführt. Dadurch führten Anpassungen in der verschachtelten Struktur für einen Benutzer plötzlich zu Auswirkungen auf andere Tests (die Daten wurden global verändert).

Vorteile:

  • Schnell
  • Einfach

Nachteile:

  • Unauffällige Bugs, Verletzung der Isolation der Umgebung

Positiver Fall

Wir implementierten copy.deepcopy(), beschrieben in der Dokumentation die Ebenen der Verschachtelung und Besonderheiten der Struktur jedes Objekts und vermieden deepcopy für große Volumina, wo man "manuelle" Teilkopien machen konnte.

Vorteile:

  • Transparenz der Umgebung
  • Unabhängigkeit der Objekte

Nachteile:

  • Erfordert Verständnis für die Struktur
  • Viel höherer Speicher- und Rechenaufwand für große Strukturen