163 votes

Python affecte plusieurs variables à la même valeur ? comportement de la liste

J'ai essayé d'utiliser l'affectation multiple comme indiqué ci-dessous pour initialiser les variables, mais je suis confus par le comportement, je m'attends à réaffecter la liste des valeurs séparément, je veux dire b[0] et c[0] égale 0 comme avant.

a=b=c=[0,3,5]
a[0]=1
print(a)
print(b)
print(c)

Le résultat est : [1, 3, 5] [1, 3, 5] [1, 3, 5]

Est-ce correct ? Que dois-je utiliser pour l'affectation multiple ? Qu'est-ce qui est différent de cela ?

d=e=f=3
e=4
print('f:',f)
print('e:',e)

résultat : ('f:', 3) ('e:', 4)

311voto

abarnert Points 94246

Si vous arrivez à Python en venant d'un langage de la famille C/Java/etc., il peut être utile d'arrêter de penser à a comme une "variable", et commencez à y penser comme un "nom".

a , b et c ne sont pas des variables différentes avec des valeurs égales ; ce sont des noms différents pour la même valeur identique. Les variables ont des types, des identités, des adresses, et toutes sortes de choses comme ça.

Les noms n'ont rien de tout cela. Valeurs bien sûr, et vous pouvez avoir beaucoup de noms pour la même valeur.

Si vous donnez Notorious B.I.G. un hot dog, * Biggie Smalls y Chris Wallace prendre un hot dog. Si vous changez le premier élément de a à 1, les premiers éléments de b y c sont 1.

Si vous voulez savoir si deux noms désignent le même objet, utilisez la fonction is opérateur :

>>> a=b=c=[0,3,5]
>>> a is b
True

Vous demandez alors :

qu'est-ce qui est différent de cela ?

d=e=f=3
e=4
print('f:',f)
print('e:',e)

Ici, vous rebranchez le nom e à la valeur 4 . Cela n'affecte pas les noms d y f de quelque manière que ce soit.

Dans votre version précédente, vous attribuiez aux a[0] et non à a . Donc, du point de vue de a[0] vous êtes en train de rebrancher a[0] mais du point de vue de a vous le modifiez sur place.

Vous pouvez utiliser le id qui vous donne un numéro unique représentant l'identité d'un objet, afin de savoir exactement quel objet est le bon, même en cas d'utilisation de la fonction is ne peut pas aider :

>>> a=b=c=[0,3,5]
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261120
>>> id(b[0])
4297261120

>>> a[0] = 1
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261216
>>> id(b[0])
4297261216

Remarquez que a[0] est passé de 4297261120 à 4297261216 - c'est maintenant un nom pour une valeur différente. Et b[0] est aussi maintenant un nom pour cette même nouvelle valeur. C'est parce que a y b nomment toujours le même objet.


Sous les couvertures, a[0]=1 appelle en fait une méthode sur l'objet liste. (C'est l'équivalent de a.__setitem__(0, 1) .) Donc, ce n'est pas vraiment de relier quoi que ce soit. C'est comme appeler my_object.set_something(1) . Bien sûr, il est probable que l'objet lie à nouveau un attribut d'instance afin d'implémenter cette méthode, mais ce n'est pas ce qui est important ; ce qui est important, c'est que vous n'assignez rien, vous ne faites que muter l'objet. Et c'est la même chose avec a[0]=1 .


user570826 a demandé :

Et si nous avions, a = b = c = 10

C'est exactement la même situation que a = b = c = [1, 2, 3] : vous avez trois noms pour la même valeur.

Mais dans ce cas, la valeur est un int et int sont immuables. Dans les deux cas, vous pouvez lier à nouveau a à une valeur différente (par exemple, a = "Now I'm a string!" ), mais cela n'affectera pas la valeur d'origine, qui est la suivante b y c seront toujours des noms pour. La différence est qu'avec une liste, vous pouvez modifier la valeur [1, 2, 3] en [1, 2, 3, 4] en faisant, par exemple, a.append(4) puisque c'est en fait changer la valeur que b y c sont des noms pour, b sera désormais b [1, 2, 3, 4] . Il n'y a aucun moyen de changer la valeur 10 en quoi que ce soit d'autre. 10 est 10 pour toujours, tout comme Claudia le vampire est 5 pour toujours (au moins jusqu'à ce qu'elle soit remplacée par Kirsten Dunst).


* Avertissement : Ne donnez pas de hot-dog à Notorious B.I.G.. Les zombies du gangsta rap ne doivent jamais être nourris après minuit.

92voto

Jimmy Kane Points 3808

Toux, toux

>>> a,b,c = (1,2,3)
>>> a
1
>>> b
2
>>> c
3
>>> a,b,c = ({'test':'a'},{'test':'b'},{'test':'c'})
>>> a
{'test': 'a'}
>>> b
{'test': 'b'}
>>> c
{'test': 'c'}
>>>

16voto

Ori Seri Points 789

En python, tout est un objet, même les types de variables "simples" (int, float, etc..).

Lorsque vous changez la valeur d'une variable, vous changez en fait son nom. pointeur et si vous comparez deux variables, c'est leur comparaison qui est faite. pointeurs . (Pour être clair, le pointeur est l'adresse dans la mémoire physique de l'ordinateur où une variable est stockée).

Par conséquent, lorsque vous changez la valeur d'une variable interne, vous changez sa valeur dans la mémoire et cela affecte toutes les variables qui pointent vers cette adresse.

Pour votre exemple, lorsque vous le faites :

a = b =  5 

Cela signifie que a et b pointent vers la même adresse en mémoire qui contient la valeur 5, mais lorsque vous le faites :

a = 6

Il n'affecte pas b car a pointe maintenant vers un autre emplacement mémoire qui contient 6 et b pointe toujours vers l'adresse mémoire qui contient 5.

Mais, quand tu le fais :

a = b = [1,2,3]

a et b, à nouveau, pointent vers le même endroit mais la différence est que si vous changez l'une des valeurs de la liste :

a[0] = 2

Cela change la valeur de la mémoire sur laquelle a pointe, mais a pointe toujours à la même adresse que b, et par conséquent, b change aussi.

14voto

Peter DeGlopper Points 25128

Oui, c'est le comportement attendu. a, b et c sont tous définis comme des étiquettes pour la même liste. Si vous voulez trois listes différentes, vous devez les affecter individuellement. Vous pouvez soit répéter la liste explicite, soit utiliser l'une des nombreuses façons de copier une liste :

b = a[:] # this does a shallow copy, which is good enough for this case
import copy
c = copy.deepcopy(a) # this does a deep copy, which matters if the list contains mutable objects

Les instructions d'affectation en Python ne copient pas les objets - elles lient le nom à un objet, et un objet peut avoir autant d'étiquettes que vous en définissez. Dans votre première édition, en changeant a[0], vous mettez à jour un élément de la liste unique à laquelle a, b et c font tous référence. Dans votre deuxième édition, en changeant e, vous changez e pour être une étiquette pour un objet différent (4 au lieu de 3).

12voto

jurgenreza Points 2201

Vous pouvez utiliser id(name) pour vérifier si deux noms représentent le même objet :

>>> a = b = c = [0, 3, 5]
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488

Les listes sont mutables ; cela signifie que vous pouvez modifier la valeur en place sans créer un nouvel objet. Cependant, cela dépend de la manière dont vous modifiez la valeur :

>>> a[0] = 1
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488
>>> print(a, b, c)
[1, 3, 5] [1, 3, 5] [1, 3, 5]

Si vous attribuez une nouvelle liste à a alors son id changera, ce qui n'affectera pas b y c Les valeurs de l'UE :

>>> a = [1, 8, 5]
>>> print(id(a), id(b), id(c))
139423880 46268488 46268488
>>> print(a, b, c)
[1, 8, 5] [1, 3, 5] [1, 3, 5]

Les nombres entiers sont immuables, vous ne pouvez donc pas modifier leur valeur sans créer un nouvel objet :

>>> x = y = z = 1
>>> print(id(x), id(y), id(z))
507081216 507081216 507081216
>>> x = 2
>>> print(id(x), id(y), id(z))
507081248 507081216 507081216
>>> print(x, y, z)
2 1 1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X