web-dev-qa-db-fra.com

python liste 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 à la liste 'b' mais la valeur de la liste 'a' a également changé.
Je pense que je ne sais pas trop pourquoi c'est comme ça (python passe les listes par référence).
Ma question est la suivante: "Comment puis-je le passer par valeur de sorte que l’ajout du" b "ne modifie pas les valeurs dans" a "?"

130
d.putto

Comme indiqué dans le officiel Python FAQ :

b = a[:]
177
phihag

Pour copier une liste, vous pouvez utiliser list(a) ou a[:]. Dans les deux cas, un nouvel objet est créé.
Cependant, ces deux méthodes ont des limites avec les collections d'objets mutables car les objets internes conservent 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 il vous faut 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]]
>>> 
124
joaquin

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
25
Kyr

Aussi, vous pouvez faire:

b = list(a)

Cela fonctionnera pour toutes les séquences, même celles qui ne prennent pas en charge les indexeurs et les tranches ...

16
Daren Thomas

Si vous souhaitez copier une liste unidimensionnelle, utilisez

b = a[:]

Cependant, si a est une liste à 2 dimensions, cela ne fonctionnera pas pour vous. Autrement dit, 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))]
9
Rohan Saxena

Comme mentionné par phihag dans sa réponse,

b = a[:]

cela fonctionnera pour votre cas car le découpage en tranches d'une liste crée un nouvel identifiant de la liste (ce qui signifie que vous ne faites plus référence au même objet dans votre mémoire et que les modifications que vous apportez à l'un ne seront pas répercutées dans l'autre.)

Cependant, il y a un léger problème. Si votre liste est multidimensionnelle, comme dans les listes dans les listes, le découpage en tranches ne résoudra pas ce problème. Les modifications apportées dans les dimensions supérieures, c'est-à-dire les listes de la liste d'origine, seront partagées entre les deux.

Ne vous inquiétez pas, il existe une solution. La copie de module a une technique de copie astucieuse qui prend en charge ce problème.

from copy import deepcopy

b = deepcopy(a)

va copier une liste avec un nouvel identifiant de mémoire, peu importe le nombre de niveaux de listes qu’elle contient!

7
Jordan Pagni

Quand vous faites b = a vous créez simplement un autre pointeur sur la même mémoire de a, c'est pourquoi lorsque vous ajoutez à b, a change aussi.

Vous devez créer copie de a et cela se fait comme ceci:

b = a[:]
5
Gil.I

Pour créer une copie d'une liste, procédez comme suit:

b = a[:]
5
Rob Wouters

J'ai trouvé que nous pouvons utiliser extend () pour implémenter la fonction copy ()

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

Je recommanderais la solution suivante:

b = []
b[:] = a

Cela copiera tous les éléments de a à b. La copie sera une copie de valeur, pas une copie de référence.

2
VHS
1
BenH