11
votes

Générer des sublistes utilisant la multiplication (*) comportement inattendu

Je suis sûr que cela a été répondu quelque part, mais je ne savais pas comment le décrire.

Disons que je souhaite créer une liste contenant 3 listes vides, comme: P>

lst = [[]]*3
lst[0] = [5]
lst[0].append(3)


4 commentaires

@Roadierich, mais les réponses ici ont une meilleure explication et des liens vers la documentation officielle.


@Aseembansal: alors ces réponses doivent être ajoutées à la question autre peut-être peut-être?


C'est définitivement un duplicata. Stackoverflow.com/ Questions / 240178 / ... et Stackoverflow.com/questions/1605024/... et Stackoverflow.com/questions 6688223 / ... et d'autres que je ne trouve pas en ce moment.


J'ai marqué les 3 questions comme des doublons.


5 Réponses :


19
votes

Ma meilleure hypothèse est que l'utilisation de la multiplication dans la forme [[]] * x provoque le stockage de Python pour stocker une référence à une seule cellule ...?

Oui. Et vous pouvez tester cela vous-même xxx

ceci indique que les trois références font référence au même objet. Et notez que vraiment est parfaitement logique que cela arrive 1 . Il suffit de copie les valeurs , et dans ce cas, les valeurs sont références. Et c'est pourquoi vous voyez la même référence répétée trois fois.

Il est intéressant de noter que si je fais xxx

Puis le "lien" de la cellule 0 est cassé et je reçois [[5,3], [], []] , mais lst [1] .append (0). cause toujours [[5,3], [0], [0] .

Vous avez changé la référence qui occupe lst [0] ; C'est-à-dire que vous avez attribué une nouvelle valeur à lst [0] . Mais vous n'avez pas changé la valeur des autres éléments, ils se réfèrent toujours au même objet qu'ils ont mentionné. Et lst [1] et lst [2] se réfère toujours à la même instance, donc bien sûr ajouter un élément à lst [1] Causes LST [2] Pour voir également ce changement.

C'est une erreur classique que les gens font des pointeurs et des références. Voici la simple analogie. Vous avez un morceau de papier. Sur cela, vous écrivez l'adresse de la maison de quelqu'un. Vous prenez maintenant cette feuille de papier et photocopiez-la deux fois pour vous retrouver avec trois morceaux de papier avec la même adresse écrite sur eux. Maintenant, prenez le premier morceau de papier, griffonnez l'adresse écrite sur elle et écrivez une nouvelle adresse pour la maison de quelqu'un d'autre . L'adresse a-t-elle écrit sur les deux autres morceaux de changement de papier? Non, c'est exactement ce que votre code a fait, cependant. C'est pourquoi les deux autres éléments ne changent pas. En outre, imaginez que le propriétaire de la maison avec adresse qui est toujours sur le deuxième morceau de papier construit un garage add-on à leur maison. Maintenant, je vous demande, la maison dont l'adresse est-elle sur le morceau de papier dispose d'un garage add-on? Oui, c'est parce que c'est exactement la même maison que celui dont l'adresse est écrite sur le morceau de papier . Cela explique tout à propos de votre deuxième exemple de code.

1 : Vous ne vous êtes pas attendu à Python d'invoquer un "Coopy Constructeur": Puke.


2 commentaires

+1 pour ID () . Cela sera utile.


Merci pour ID (x) , et le garage intégré est un bon exemple pour l'édition de pointeur.



5
votes

Ceci est parce que la multiplication de séquence répète simplement les références. Lorsque vous écrivez [[]] * 2 , vous créez une nouvelle liste avec deux éléments, mais ces deux éléments sont l'objet même en mémoire, à savoir une liste vide. Par conséquent, un changement d'un est reflété dans l'autre. La compréhension, en revanche, crée une nouvelle liste nouvelle et indépendante sur chaque itération: xxx


2 commentaires

Je n'ai pas pensé à essayer l'opérateur "est", merci!


@Adrianwan pas de problème, heureux d'aider.



5
votes

Ils référennent les mêmes listes.

Il y a des questions similaires ici et ici

et du FAQ :

"* Ne crée pas de copies, cela ne crée que des références à l'existant objets. "


1 commentaires

+1 pour le lien vers les documents Python.



1
votes

Vous devinez que l'utilisation de la multiplication dans la forme [[]] * x provoque la conservation d'une référence à une seule cellule.

Donc, vous vous retrouvez avec une liste de 3 références à la même liste.


0 commentaires

1
votes

Fondamentalement, ce qui se passe dans votre premier exemple, c'est qu'une liste est créée avec plusieurs références à la même liste intérieure. Voici une ventilation.

>>> c = [[], [], []]  # this line creates four different lists
>>> d = [ [] for _ in xrange(3) ]  # so does this line
>>> c[0].append(4)
>>> d[0].append(5)
>>> print c
[[4], [], []]
>>> print d
[[5], [], []]


0 commentaires