ProgrammationIngénieur de données

Expliquez la différence entre la copie superficielle (shallow copy) et la copie profonde (deep copy), ainsi que le comportement de copy.copy et copy.deepcopy lors de la copie d'objets complexes. Donnez un exemple où une mauvaise compréhension a conduit à un bug.

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

La copie superficielle (shallow copy) crée un nouvel objet de niveau supérieur, mais les objets imbriqués (éléments de listes, dictionnaires imbriqués, etc.) partagent la mémoire avec l'original. La copie profonde (deep copy) copie récursivement tous les niveaux des objets.

On peut utiliser le module copy :

import copy original = [[1, 2], [3, 4]] shallow = copy.copy(original) deep = copy.deepcopy(original) shallow[0][0] = 99 # Change à la fois original et shallow print(original) # [[99, 2], [3, 4]] # Maintenant avec deep original = [[1, 2], [3, 4]] deep = copy.deepcopy(original) deep[0][0] = 99 print(original) # [[1, 2], [3, 4]]

Caractéristiques :

  • copy.copy(obj): ne copie que "l'enveloppe"
  • copy.deepcopy(obj): copie récursive complète
  • Certains objets (par exemple, fichiers ouverts, sockets) ne sont pas copiés par deep copy (exception)

Question piège.

Que se passe-t-il lors de la copie d'un tuple qui contient des objets modifiables ?

Réponse avec exemple :

tuple est immuable, mais ses éléments peuvent être modifiables (par exemple, une liste). La copie superficielle et la copie profonde diffèrent :

import copy t = ([1, 2], [3, 4]) shallow = copy.copy(t) deep = copy.deepcopy(t) shallow[0][0] = 99 print(t) # ([99, 2], [3, 4]) # Lors de la deep copy : t = ([1, 2], [3, 4]) deep = copy.deepcopy(t) deep[0][0] = 88 print(t) # ([1, 2], [3, 4])

Exemples d'erreurs réelles dues à une méconnaissance des subtilités du sujet.


Histoire

Dans une application de traitement de documents, les données étaient stockées dans une liste à l'intérieur d'un dictionnaire. Lors de la copie d'objets à l'aide de copy.copy, les éléments imbriqués étaient accidentellement modifiés lors de la modification du nouvel objet. En conséquence, les données d'origine ont été modifiées dans d'autres parties du système ! Cela a causé une corruption de données. Cela a été corrigé en remplaçant par deepcopy.


Histoire

Dans un projet de machine learning, lors de l'enregistrement des hyperparamètres des modèles, nous copions la liste des configurations par affectation standard et shallow copy, après quoi différentes expériences modifiaient mutuellement leurs paramètres. La source du bug a été trouvée après un diagnostic du comportement de la copie des listes imbriquées via deepcopy.


Histoire

Dans un logiciel financier, deep copy a été accidentellement appliqué à un objet incluant un fichier ouvert (handle), ce qui a provoqué TypeError: cannot pickle '_io.TextIOWrapper' object — parce que copy.deepcopy utilise pickle en interne. Cela a été corrigé par un traitement explicite de tels champs ou par un appel à shallow copy.