Copie d'un objet
From Wikipedia, the free encyclopedia
La copie d'un objet est l'action, en programmation informatique, de reproduire ou copier les attributs d'un objet dans un autre objet. Un objet a le plus souvent un type de données composite (en) dans les langages de programmation orientés objet.
La copie d'objet est une opération basique. Le plus souvent, elle est faite en copiant récursivement les attributs de l'objet source vers l'objet cible. Cependant, ce travail peut être inutilement coûteux, ou même impossible à cause de la nature de l'objet. Ces contraintes conduisent à envisager différentes formes de copie, jouant essentiellement sur la profondeur jusqu'à laquelle est faite la copie.
Copie de référence
La copie de référence est une copie à profondeur zéro : seule l'adresse de l'objet complet est copiée. Cela permet d'utiliser l'objet sous un nouveau nom ou à un autre endroit (passage par référence), ou de le placer au sein d'un agrégat.
Si B est une copie de la référence de A, alors B est juste un autre nom pour A, jusqu'à ce qu'une autre référence soit affectée à l'une des deux variables.
Les références sont une légère abstraction des pointeurs et des adresses que l'on trouve dans les langages bas niveau comme le C. Une copie de pointeur est une copie de référence.
La référence (ou le pointeur) est en fait elle-même un objet (qui sert à accéder à un autre objet), et c'est ce type d'objet qui est créé et copié.
La copie de référence est très peu coûteuse et est toujours possible. Cependant, elle n'offre pas de nouvel objet qui peut être modifié indépendamment de l'objet d'origine. De plus, le fait de passer par une adresse stockée en mémoire pour accéder à l'objet peut impacter négativement les performances, par rapport à une situation où l'objet est copié dans la pile système.
Exemple en Python :
A = [1, 2]
B = A # B référence le même objet (une liste) que A
B.append(3) # ajoute un élément à la liste
print(A) # affiche [1, 2, 3]
A = [4, 5] # crée un autre objet
print(B) # affiche [1, 2, 3], car B référence toujours le premier objet
Notons qu'en Python, les objets d'un type numérique (comme les entiers) ne peuvent pas être modifiés, c'est pourquoi ils n'offrent pas la sensation d'être référencés par plusieurs variables.
Copie superficielle
La copie superficielle (en anglais shallow copy) est une copie à profondeur 1. C'est une copie des champs d'un objet dans un autre objet. Si tous ces champs sont d'un type primitif, elle est équivalente à une copie profonde (et on parlera alors plutôt de copie profonde). Si certains champs sont des références, elle donne lieu à la copie de ces références. Si certains champs sont d'un type composite, alors seule leur référence doit être copiée pour obtenir une copie superficielle.
La copie superficielle est généralement rapide et permet de composer un nouvel objet basé sur un objet d'origine sans modifier ce dernier, mais seulement au premier niveau de profondeur.
Exemple en Python :
A = [[1], [2, 3]]
B = A[:] # B est une copie superficielle de A
B.append([4, 5]) # ajoute un élément à la liste référencée par B
B[0].append(6) # ajoute un élément à la première liste d'entiers
print(A) # affiche [[1, 6], [2, 3]]
Copie profonde
La copie profonde (en anglais deep copy) est une copie à profondeur infinie. Elle consiste à copier tout le graphe (le plus souvent un arbre) d'objets contenus dans un objet, dans de nouvelles adresses qui sont reprises dans la copie. Le nouvel objet est alors complètement indépendant de l'objet d'origine.
C'est la forme de copie la plus coûteuse, à la fois en temps et en mémoire. Elle peut aussi nécessiter quelques efforts de programmation. Notamment, si l'objet contient des références cycliques, il faudra les repérer pour éviter une récursion infinie. Par ailleurs, la copie profonde peut être impossible pour une ressource telle qu'une connexion à un serveur ou l'accès en écriture à un fichier.
Exemple en Python :
from copy import deepcopy
A = [[1], [2, 3]]
B = deepcopy(A) # B a le même contenu que A mais est indépendant
B.append([4])
B[0].append(5)
print(A) # affiche [[1], [2, 3]]
Copie paresseuse
La copie paresseuse (en anglais lazy copy) est une combinaison des deux stratégies précédentes. Elle consiste à utiliser initialement une copie superficielle (ou même une copie de référence), puis à remplacer cette copie par une copie profonde quand il devient question de modifier l'objet, si l'objet d'origine est toujours utilisé dans le programme, afin d'éviter de le modifier. Cette technique fait intervenir un comptage de références. Il s'agit d'un cas de copy-on-write. Si la copie profonde n'est jamais effectuée, la copie paresseuse est alors aussi efficace que la copie superficielle.


