8.10. copy — Opérations de copie superficielle et récursive

Code source : Lib/copy.py


Les instructions d’affectation en Python ne copient pas les objets, elles créent des liens entre la cible et l’objet. Concernant les collections qui sont muables ou contiennent des éléments muables, une copie est parfois nécessaire, pour pouvoir modifier une copie sans modifier l’autre. Ce module met à disposition des opérations de copie génériques superficielle et récursive (comme expliqué ci-dessous).

Résumé de l’interface :

copy.copy(x)

Renvoie une copie superficielle de x.

copy.deepcopy(x)

Renvoie une copie récursive de x.

exception copy.error

Levée pour les erreurs spécifiques au module.

La différence entre copie superficielle et récursive n’est pertinente que pour les objets composés (objets contenant d’autres objets, comme des listes ou des instances de classe) :

  • Une copie superficielle construit un nouvel objet composé puis (dans la mesure du possible) insère dans l’objet composé des références aux objets trouvés dans l’original.
  • Une copie récursive (ou profonde) construit un nouvel objet composé puis, récursivement, insère dans l’objet composé des copies des objets trouvés dans l’objet original.

On rencontre souvent deux problèmes avec les opérations de copie récursive qui n’existent pas avec les opérations de copie superficielle :

  • Les objets récursifs (objets composés qui, directement ou indirectement, contiennent une référence à eux-mêmes) peuvent causer une boucle récursive.
  • Because deep copy copies everything it may copy too much, such as data which is intended to be shared between copies.

La fonction deepcopy() évite ces problèmes en :

  • gardant en mémoire dans un dictionnaire les objets déjà copiés durant la phase de copie actuelle ; et
  • laissant les classes créées par l’utilisateur écraser l’opération de copie ou l’ensemble de composants copiés.

Ce module ne copie pas les types tels que module, méthode, trace d’appels, cadre de pile, fichier, socket, fenêtre, tableau, ou tout autre type similaire. Il « copie » les fonctions et les classes (superficiellement et récursivement), en retournant l’objet original inchangé ; c’est compatible avec la manière dont ils sont traités par le module pickle.

Les copies superficielles de dictionnaires peuvent être faites en utilisant dict.copy(), et de listes en affectant un slice de la liste, par exemple, copied_list = original_list[:].

Les classes peuvent utiliser les mêmes interfaces de contrôle que celles utilisées pour la sérialisation. Voir la description du module pickle pour plus d’informations sur ces méthodes. En effet, le module copy utilise les fonctions de sérialisation enregistrées à partir du module copyreg.

Afin qu’une classe définisse sa propre implémentation de copie, elle peut définir les méthodes spéciales __copy__() et __deepcopy__(). La première est appelée pour implémenter l’opération de copie superficielle ; aucun argument supplémentaire n’est passé. La seconde est appelée pour implémenter l’opération de copie récursive ; elle reçoit un argument, le dictionnaire memo. Si l’implémentation de __deepcopy__() a besoin de faire une copie récursive d’un composant, elle devrait appeler la fonction deepcopy() avec le composant comme premier argument et le dictionnaire memo comme second argument.

Voir aussi

Module pickle
Discussion sur les méthodes spéciales utilisées pour gérer la récupération et la restauration de l’état d’un objet.