web-dev-qa-db-fra.com

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

J'ai essayé d'utiliser plusieurs affectations, comme indiqué ci-dessous, pour initialiser les variables, mais le comportement m'a confondu. Je m'attends à réaffecter la liste des valeurs séparément. Je veux dire que b [0] et c [0] sont égaux à 0 comme auparavant.

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 exact? Que dois-je utiliser pour une affectation multiple? Qu'est-ce qui est différent de ça?

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

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

106
Marco

Si vous venez à Python à partir d’un langage dans C/Java/etc. famille, cela peut vous aider à cesser de penser à a en tant que "variable" et à commencer à le penser en tant que "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 de ce genre.

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

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

Si vous voulez savoir si deux noms nomment le même objet, utilisez l'opérateur is:

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

Vous demandez alors:

qu'est-ce qui est différent de ça?

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

Ici, vous reliez le nom e à la valeur 4. Cela n'affecte en aucune façon les noms d et f.

Dans votre version précédente, vous affectiez à a[0] et non à a. Donc, du point de vue de a[0], vous reliez a[0], mais du point de vue de a, vous le modifiez sur place.

Vous pouvez utiliser la fonction id, qui vous donne un numéro unique représentant l'identité d'un objet, pour voir exactement quel objet est lequel même si is ne peut pas vous 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

Notez que a[0] est passé de 4297261120 à 4297261216 - il s'agit maintenant d'un nom pour une valeur différente. Et b[0] est également un nom pour cette même nouvelle valeur. En effet, a et b continuent de nommer le même objet.


Sous les couvertures, a[0]=1 appelle en fait une méthode sur l'objet liste. (Cela équivaut à a.__setitem__(0, 1).) Donc, ce n'est pas vraiment rien relier du tout. C'est comme appeler my_object.set_something(1). Bien sûr, l’objet est probablement en train de relier 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'attribuez rien, vous ne faites que muter l'objet. Et c'est pareil avec a[0]=1.


user570826 a demandé:

Et si nous avons, 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 ints sont immuables. Dans les deux cas, vous pouvez relier a à une valeur différente (par exemple, a = "Now I'm a string!"), mais n'affectera pas la valeur d'origine, qui b et c être des noms pour. La différence est qu'avec une liste, vous pouvez changer la valeur [1, 2, 3] en [1, 2, 3, 4] en faisant, par exemple, a.append(4); puisque cela change en fait la valeur que b et c sont des noms pour, b va maintenant b [1, 2, 3, 4]. Il n'y a aucun moyen de changer la valeur 10 en autre chose. 10 a 10 ans pour toujours, tout comme Claudia la vampire a 5 ans pour toujours (au moins jusqu'à ce qu'elle soit remplacée par Kirsten Dunst).


* Attention: Ne donnez pas Notorious B.I.G. un hot dog. Les zombies de gangsta rap ne devraient jamais être nourris après minuit.

235
abarnert

Tousse tousse

>>> 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'}
>>> 
49
Jimmy Kane

Oui, c'est le comportement attendu. a, b et c sont tous définis comme étiquettes pour la même liste. Si vous souhaitez trois listes différentes, vous devez les affecter individuellement. Vous pouvez répéter la liste explicite ou utiliser l’un des nombreux moyens 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'assignation dans Python ne copient pas les objets - elles lient le nom à un objet et un objet peut avoir autant d'étiquettes que vous avez définies. Lors de votre première modification, en modifiant a [0], vous mettez à jour un élément de la liste unique auquel a, a, b et c font tous référence. Dans le second, en changeant e, vous changez e pour être une étiquette pour un objet différent (4 au lieu de 3).

13
Peter DeGlopper

En python, tout est un objet, ainsi que des types de variables "simples" (int, float, etc.).

Lorsque vous modifiez une valeur de variable, vous modifiez en fait son pointeur, et si vous comparez entre deux variables, il compare leurs pointeurs. (Pour être clair, le pointeur est l'adresse dans la mémoire de l'ordinateur physique où une variable est stockée).

Par conséquent, lorsque vous modifiez une valeur de variable interne, vous modifiez sa valeur dans la mémoire et elle affecte toutes les variables qui pointent vers cette adresse.

Pour votre exemple, quand vous faites:

a = b =  5 

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

a = 6

Cela n'a pas d'incidence sur b, car a pointe maintenant sur un autre emplacement mémoire contenant 6 et b pointe toujours sur l'adresse mémoire qui contient 5.

Mais quand tu le fais:

a = b = [1,2,3]

encore une fois, a et b indiquent le même emplacement, mais la différence est que si vous modifiez l'une des valeurs de la liste:

a[0] = 2

Cela modifie la valeur de la mémoire sur laquelle a est pointé, mais a est toujours dirigé vers la même adresse que b et, par conséquent, b change également.

12
Ori Seri

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 modifiables; cela signifie que vous pouvez modifier la valeur en place sans créer un nouvel objet. Cependant, cela dépend de la façon 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 assignez une nouvelle liste à a, son identifiant changera donc les valeurs de b et c ne seront pas affectées:

>>> 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 entiers étant immuables, vous ne pouvez pas changer la 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
9
jurgenreza

dans votre premier exemple a = b = c = [1, 2, 3] vous dites vraiment:

 'a' is the same as 'b', is the same as 'c' and they are all [1, 2, 3]

Si vous voulez définir "a" égal à 1, "b" égal à "2" et "c" égal à 3, essayez ceci:

a, b, c = [1, 2, 3]

print(a)
--> 1
print(b)
--> 2
print(c)
--> 3

J'espère que cela t'aides!

6
Nick Burns

Ce dont vous avez besoin est ceci:

a, b, c = [0,3,5] # Unpack the list, now a, b, and c are ints
a = 1             # `a` did equal 0, not [0,3,5]
print(a)
print(b)
print(c)
3
pydsigner

En termes simples, dans le premier cas, vous attribuez plusieurs noms à un list. Une seule copie de la liste est créée en mémoire et tous les noms font référence à cet emplacement. Donc, changer la liste en utilisant l’un des noms modifiera la liste en mémoire.

Dans le second cas, plusieurs copies de même valeur sont créées en mémoire. Donc, chaque copie est indépendante l’une de l’autre.

3
Vikas

Le code qui fait ce dont j'ai besoin pourrait être ceci:

# test

aux=[[0 for n in range(3)] for i in range(4)]
print('aux:',aux)

# initialization

a,b,c,d=[[0 for n in range(3)] for i in range(4)]

# changing values

a[0]=1
d[2]=5
print('a:',a)
print('b:',b)
print('c:',c)
print('d:',d)

Résultat:

('aux:', [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]])
('a:', [1, 0, 0])
('b:', [0, 0, 0])
('c:', [0, 0, 0])
('d:', [0, 0, 5])
2
Marco