ProgrammatiePython Developer (middleware, backend, tests)

Hoe implementeer je correct het kopiëren van verzamelingen in Python, in welke gevallen is copy() niet voldoende en waarom is deep copy nodig?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

Achtergrond: In Python is het kopiëren van objecten (vooral verzamelingen — lijsten, dictionaries) cruciaal: eenvoudige toewijzing van een variabele creëert een nieuwe referentie, geen kopie. Speciale methoden copy() en deepcopy() zijn ontwikkeld om ongewenste "bijwerkingen" bij het gezamenlijk gebruik van structuren te voorkomen.

Probleem: Bij het werken met geneste verzamelingen (lijst van lijsten, dictionary binnen een dictionary) reproduceert een eenvoudige copy() alleen de container zelf, maar niet de interne elementen. Dit kan leiden tot moeilijk te traceren bugs: wijziging van een genesteld element wordt weerspiegeld in alle "kopieën".

Oplossing: copy.copy() creëert een oppervlakkige kopie (shallow copy) — een nieuwe container op het hoogste niveau, maar de geneste objecten blijven dezelfde. copy.deepcopy() kopieert recursief alle geneste objecten.

Voorbeeldcode:

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]] — het geneste object is gewijzigd! print(deep) # [[1, 2], [3, 4]] — deepcopy heeft de oorspronkelijke toestand behouden

Belangrijke kenmerken:

  • Eenvoudige toewijzing kopieert alleen de referentie, geen duplicatie
  • .copy() (of copy.copy()) kopieert de "buitenste" container, maar niet de geneste objecten
  • .deepcopy() wordt gebruikt voor volledige onafhankelijkheid van kopieën

Vragen met een valstrik.

Is het soms voldoende om lst2 = lst[:] te schrijven voor het kopiëren van een lijst?

lst2 = lst[:] creëert een oppervlakkige kopie van de lijst, maar de geneste objecten (bijvoorbeeld lijsten binnen de lijst) blijven dezelfde. Voor platte lijsten is dit voldoende; voor geneste structuren is dat niet het geval.

Voorbeeld:

lst = [[1], [2]] lst2 = lst[:] lst[0][0] = 99 print(lst2) # [[99], [2]] — het geneste element is gewijzigd in beide "kopieën"

Werkt de methode .copy() hetzelfde voor alle verzamelingen?

Nee. Bijvoorbeeld, dict.copy() werkt als oppervlakkig kopiëren, list.copy() is pas beschikbaar sinds Python 3.3, en voor set is er set.copy(). Voor gebruikersobjecten hangt de ondersteuning van .copy() af van de geïmplementeerde methode.


Kun je overal deepcopy gebruiken? Is dat veilig en efficiënt?

Nee. deepcopy is een kostbare operatie: het kan prestatieproblemen veroorzaken, vooral bij grote structuren, en het faalt bij niet-kopieerbare/sluitende of niet-standaard objecten. Gebruik deepcopy alleen wanneer je echt een volledig onafhankelijke, recursieve kopie nodig hebt.


Typische fouten en anti-patronen

  • Gebruik van eenvoudige toewijzing of .copy() in plaats van deepcopy voor geneste structuren
  • Het toepassen van deepcopy op alle objecten achtereenvolgens (vertraagt het programma)
  • Pogingen om objecten te kopiëren die geen kopiëren ondersteunen (bijvoorbeeld bestanden, stromingen)

Voorbeeld uit het leven

Negatieve case

In tests werden kopieën van een "dictionary van dictionaries" gemaakt via dict.copy(). Hierdoor betroffen wijzigingen in de geneste structuur voor één gebruiker plotseling andere tests (de gegevens mutateerden globaal).

Voordelen:

  • Snel
  • Eenvoudig

Nadelen:

  • Onzichtbare bugs, schending van isolatie van omgeving

Positieve case

We hebben copy.deepcopy() geïmplementeerd, de niveau van genestheid en eigenschappen van de structuur van elk object in de documentatie beschreven, en deepcopy vermeden voor grote volumes waar "handmatige" kopieën per deel mogelijk waren.

Voordelen:

  • Transparantie van omgeving
  • Onafhankelijkheid van objecten

Nadelen:

  • Vereist begrip van de structuur
  • Veel groter geheugen- en processorverbruik voor grote structuren