2011-02-01 3 views
3

Autant j'aime Python, les trucs de référence et deepcopy me font parfois peur.Deepcopy sur les listes référencées imbriquées créées par la multiplication de liste ne fonctionne pas

Pourquoi ne deepcopy fonctionne pas ici:

>>> import copy 
>>> a = 2*[2*[0]] 
>>> a 
[[0, 0], [0, 0]] 
>>> b = copy.deepcopy(a) 
>>> b[0][0] = 1 
>>> b 
[[1, 0], [1, 0]]  #should be: [[1, 0], [0, 1]] 
>>> 

J'utilise un tableau numpy comme workarround dont j'ai besoin plus tard de toute façon. Mais j'avais vraiment espéré que si j'utilisais deepcopy, je n'aurais plus à chercher de références non-désirées. Y a-t-il d'autres pièges où ça ne marche pas?

Répondre

10

Cela ne fonctionne pas car vous créez un tableau avec deux références au même tableau.

Une approche alternative est:

[[0]*2 for i in range(2)] 

Ou plus explicite:

[[0 for j in range(2)] for i in range(2)] 

Cela fonctionne parce qu'il crée un nouveau tableau à chaque itération.

Y a-t-il d'autres pièges dans lesquels cela ne fonctionne pas?

Chaque fois que vous avez un tableau contenant des références, vous devez faire attention. Par exemple [Foo()] * 2 n'est pas le même que [Foo() for i in range(2)]. Dans le premier cas, un seul objet est construit et le tableau contient deux références à celui-ci. Dans le second cas, deux objets distincts sont construits.

+1

+1 pour bien faire les choses. –

+0

Merci pour les réponses rapides. J'apprécie votre solution élégante. Pourtant, il me semble que le manuel deepcopy est trompeur ("Une copie profonde construit un nouvel objet composé puis, récursivement, insère * des copies * dans les objets trouvés dans l'original."). Ce serait bien d'avoir une fonction qui ferait ce que je m'attendrais à ce que deepcopy fasse: se débarrasser de toutes les références doubles. – Gonzo

7

Fonctionne exactement comme vous l'avez prévu.

a = 2 * [2 * [0]]

Lorsque vous multipliez [[0,0]] avec 2 *, les deux éléments de la nouvelle liste pointera vers la même liste [0,0]. a[0] et a[1] sont la même liste, car la référence est copiée, pas les données (ce qui serait impossible). Changer le premier élément de l'un d'eux change le premier élément de l'autre.

copy.deepcopy copie la liste correctement, en préservant des objets uniques.

+0

+1 pour la raison pour laquelle cela ne fonctionne pas. –

Questions connexes