python liste par valeur pas par référence [dupliquer]
cette question a déjà une réponse ici:
- comment cloner ou copier une liste? 18 réponses
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 je pense que j'ai peu d'idée pourquoi c'est comme ça (python passe les listes par référence).
Ma question Est "Comment puis-je passer par la valeur de sorte que l'ajout de" b "ne change pas les valeurs de "a"?"
11 réponses
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 limites avec les collections d'objets mutables comme les objets intérieurs 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 copie.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 performance ma réponse préférée serait:
b.extend(a)
vérifier comment les solutions de remplacement se comparent en termes de performance:
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
vous pouvez aussi faire:
b = list(a)
cela fonctionnera pour n'importe quelle séquence, même ceux qui ne supportent pas les indexeurs et les tranches...
si vous voulez copier une liste unidimensionnelle, utilisez
b = a[:]
cependant, si a
est une liste bidimensionnelle, cela ne va pas fonctionner pour vous. C'est-à-dire que tout changement dans a
sera aussi 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))]
quand vous faites b = a
vous créez simplement un autre pointeur vers la même mémoire de a ,
c'est pourquoi, lorsque vous ajoutez aux b , un trop de changements.
vous devez créer copier de a et c'est fait comme ceci:
b = a[:]
comme l'a mentionné phihag dans sa réponse,
b = a[:]
fonctionnera pour votre cas puisque trancher une liste crée un nouvel id de mémoire de la liste (ce qui signifie que vous ne faites plus référence au même objet dans votre mémoire et les changements que vous faites à l'un ne seront pas reflétés dans l'autre.)
Cependant, il y a un léger problème. Si votre liste est multidimensionnelle, comme dans les listes à l'intérieur des listes, le simple découpage ne résoudra pas ce problème. Les modifications apportées dans les dimensions supérieures, c'est-à-dire les listes de la liste originale, seront partagées entre les deux.
ne vous inquiétez pas, il y a une solution. La copie de module a une technique de copie astucieuse qui prend soin de cette question.
from copy import deepcopy
b = deepcopy(a)
copiera une liste avec un nouvel identifiant de mémoire peu importe le nombre de niveaux de listes qu'elle contient!
j'ai trouvé que nous pouvons utiliser extend () pour implémenter la fonction de copy ()
a=['help', 'copyright', 'credits', 'license']
b = []
b.extend(a)
b.append("XYZ")
je recommande 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.