ProgrammationDéveloppeur Python (middleware, backend, tests)

Comment réaliser correctement la copie de collections en Python, dans quels cas copy() est insuffisant et pourquoi, et quand un deep copy est-il nécessaire ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question : En Python, la copie d'objets (en particulier des collections - listes, dictionnaires) est critique : une simple attribution à une variable crée une nouvelle référence, pas une copie. Les méthodes spéciales copy() et deepcopy() sont apparues pour éviter les "effets secondaires" indésirables lors de l'utilisation conjointe de structures.

Problème : Lors de la manipulation de collections imbriquées (liste de listes, dictionnaire dans un dictionnaire), un simple copy() reproduit uniquement le conteneur lui-même, mais pas les éléments internes. Cela peut entraîner des bugs difficiles à détecter : la modification d'un élément imbriqué se reflète dans toutes les "copies".

Solution : copy.copy() crée une copie superficielle (shallow copy) - un nouveau conteneur de premier niveau, mais les objets imbriqués restent les mêmes. copy.deepcopy() copie récursivement tous les objets imbriqués.

Exemple de code :

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]] — l'objet imbriqué a changé ! print(deep) # [[1, 2], [3, 4]] — deepcopy a conservé l'état initial

Caractéristiques clés :

  • Une simple attribution ne fait que copier la référence, aucun doublon
  • .copy() (ou copy.copy()) copie le conteneur "extérieur", mais pas les objets imbriqués
  • .deepcopy() est utilisé pour une indépendance totale des copies

Questions piégeuses.

Est-il parfois suffisant d'écrire lst2 = lst[:] pour copier une liste ?

lst2 = lst[:] crée une copie superficielle de la liste, mais les objets imbriqués (par exemple, des listes à l'intérieur de la liste) resteront les mêmes. Pour des listes plates - cela suffit ; pour des structures imbriquées - ce n'est pas le cas.

Exemple :

lst = [[1], [2]] lst2 = lst[:] lst[0][0] = 99 print(lst2) # [[99], [2]] — l'élément imbriqué a changé dans les deux "copys"

La méthode .copy() fonctionne-t-elle de la même manière pour toutes les collections ?

Non. Par exemple, dict.copy() fonctionne comme une copie superficielle, list.copy() n'est apparu qu'avec Python 3.3, pour set - il y a set.copy(). Pour les objets personnalisés, le support de .copy() dépend de la méthode implémentée.


Peut-on se passer de deepcopy partout ? Est-ce sûr et efficace ?

Non. deepcopy est une opération coûteuse : elle peut provoquer des problèmes de performance, surtout sur de grandes structures, et elle échoue sur des objets non copiables/fermant ou non standards. Utilisez deepcopy seulement quand vous avez vraiment besoin d'une copie entièrement indépendante et récursive.


Erreurs typiques et anti-patterns

  • Utiliser une simple attribution ou .copy() au lieu de deepcopy pour des structures imbriquées
  • Appliquer deepcopy à tous les objets à la suite (ralentit le programme)
  • Essayer de copier des objets qui ne supportent pas la copie (par exemple, des fichiers, des flux)

Exemple de la vie réelle

Cas négatif

Dans les tests, une copie d'un "dictionnaire de dictionnaires" a été réalisée via dict.copy(). En raison de cela, des modifications dans la structure imbriquée pour un utilisateur ont soudainement affecté d'autres tests (les données étaient mutées globalement).

Avantages :

  • Rapide
  • Simple

Inconvénients :

  • Bugs peu évidents, rupture de l'isolement de l'environnement

Cas positif

Nous avons intégré copy.deepcopy(), décrit dans la documentation le niveau d'imbrication et les caractéristiques de la structure de chaque objet, évité deepcopy pour de gros volumes, où une "copie manuelle" par morceaux était possible.

Avantages :

  • Transparence de l'environnement
  • Indépendance des objets

Inconvénients :

  • Nécessite une compréhension de la structure
  • Bien plus de consommation de mémoire et de temps processeur pour de grandes structures