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 "?"
Comme indiqué dans le officiel Python FAQ :
b = a[:]
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]]
>>>
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
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 ...
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))]
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!
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[:]
Pour créer une copie d'une liste, procédez comme suit:
b = a[:]
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")
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.
b = list(a)