196 votes

liste python par valeur et non par référence

Prenons un exemple

 a=['help', 'copyright', 'credits', 'license']
b=a
b.append('XYZ')
b
['help', 'copyright', 'credits', 'license', 'XYZ']
a
['help', 'copyright', 'credits', 'license', 'XYZ']

Je voulais ajouter une valeur dans la liste 'b' mais la valeur de la liste 'a' a également changé. Je pense que je n'ai aucune idée de pourquoi c'est comme ça (python passe des listes par référence). Ma question est "comment puis-je le passer par valeur pour que l'ajout de 'b' ne change pas les valeurs dans 'a' ?"

276voto

phihag Points 89765

Vous ne pouvez rien passer par valeur en Python. Si vous souhaitez faire une copie de a , vous pouvez le faire explicitement, comme décrit dans la FAQ Python officielle :

 b = a[:]

159voto

joaquin Points 22450

Pour copier une liste, vous pouvez utiliser list(a) ou a[:] . Dans les deux cas, un nouvel objet est créé. Ces deux méthodes, cependant, ont des limitations avec les collections d'objets mutables car les objets internes gardent leurs références intactes :

 >>> a = [[1,2],[3],[4]]

>>> b = a[:]
>>> c = list(a)

>>> c[0].append(9)

>>> a
[[1, 2, 9], [3], [4]]
>>> c
[[1, 2, 9], [3], [4]]
>>> b
[[1, 2, 9], [3], [4]]
>>> 

Si vous voulez une copie complète de vos objets, vous avez besoin de copy.deepcopy

 >>> from copy import deepcopy
>>> a = [[1,2],[3],[4]]

>>> b = a[:]
>>> c = deepcopy(a)

>>> c[0].append(9)

>>> a
[[1, 2], [3], [4]]
>>> b
[[1, 2], [3], [4]]
>>> c
[[1, 2, 9], [3], [4]]
>>> 

40voto

Kyr Points 1961

En termes de performances, ma réponse préférée serait :

 b.extend(a)

Vérifiez comment les alternatives associées se comparent les unes aux autres en termes de performances :

 In [1]: import timeit

In [2]: timeit.timeit('b.extend(a)', setup='b=[];a=range(0,10)', number=100000000)
Out[2]: 9.623248100280762

In [3]: timeit.timeit('b = a[:]', setup='b=[];a=range(0,10)', number=100000000)
Out[3]: 10.84756088256836

In [4]: timeit.timeit('b = list(a)', setup='b=[];a=range(0,10)', number=100000000)
Out[4]: 21.46313500404358

In [5]: timeit.timeit('b = [elem for elem in a]', setup='b=[];a=range(0,10)', number=100000000)
Out[5]: 66.99795293807983

In [6]: timeit.timeit('for elem in a: b.append(elem)', setup='b=[];a=range(0,10)', number=100000000)
Out[6]: 67.9775960445404

In [7]: timeit.timeit('b = deepcopy(a)', setup='from copy import deepcopy; b=[];a=range(0,10)', number=100000000)
Out[7]: 1216.1108016967773

20voto

Daren Thomas Points 26812

Aussi, vous pouvez faire :

 b = list(a)

Cela fonctionnera pour n'importe quelle séquence, même celles qui ne prennent pas en charge les indexeurs et les tranches...

17voto

Rohan Saxena Points 631

Si vous souhaitez copier une liste unidimensionnelle, utilisez

 b = a[:]

Cependant, si a est une liste à 2 dimensions, cela ne fonctionnera pas pour vous. C'est-à-dire que tout changement dans a sera également reflété dans b . Dans ce cas, utilisez

 b = [[a[x][y] for y in range(len(a[0]))] for x in range(len(a))]

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