python liste par valeur pas par référence [dupliquer]

cette question a déjà une réponse ici:

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"?"

106
demandé sur Benjamin Gruenbaum 2012-01-05 18:28:51

11 réponses

comme répondu dans le FAQ Python officiel :

b = a[:]
153
répondu phihag 2012-01-05 14:30:08

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]]
>>> 
114
répondu joaquin 2015-07-31 22:14:55

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
19
répondu Kyr 2016-01-06 16:33:50

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...

14
répondu Daren Thomas 2012-01-05 14:32:16

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))]
9
répondu Rohan Saxena 2018-04-23 09:34:41

pour créer une copie d'une liste faites ceci:

b = a[:]
5
répondu Rob Wouters 2012-01-05 14:30:30

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[:]
5
répondu Gil.I 2012-01-05 14:36:03

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!

5
répondu Jordan Pagni 2017-02-24 23:07:45

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") 
2
répondu user3754245 2014-07-03 23:10:08

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.

2
répondu VHS 2017-11-19 22:04:11
1
répondu BenH 2012-01-05 14:32:33