Quelles sont les options pour cloner ou copier une liste en Python?
Lorsque vous utilisez new_list = my_list
, toute modification apportée à new_list
change my_list
à tout moment. Pourquoi est-ce?
Avec new_list = my_list
, vous n'avez pas réellement deux listes. L'affectation ne fait que copier la référence dans la liste, pas dans la liste réelle. Ainsi, new_list
et my_list
font référence à la même liste après l'affectation.
Pour copier réellement la liste, vous avez différentes possibilités:
Vous pouvez utiliser la méthode intégrée list.copy()
(disponible depuis Python 3.3):
new_list = old_list.copy()
Vous pouvez le trancher:
new_list = old_list[:]
Alex Martelli l'opinion (au moins retour en 2007 ) à ce sujet est que c'est une syntaxe étrange et que cela n'a pas de sens de l'utiliser déjà. ;) (À son avis, le suivant est plus lisible).
Vous pouvez utiliser la fonction intégrée list()
:
new_list = list(old_list)
Vous pouvez utiliser le générique copy.copy()
:
import copy
new_list = copy.copy(old_list)
Ceci est un peu plus lent que list()
car il doit d'abord trouver le type de données de old_list
.
Si la liste contient des objets et que vous souhaitez également les copier, utilisez le nom générique copy.deepcopy()
:
import copy
new_list = copy.deepcopy(old_list)
De toute évidence, la méthode la plus lente et la plus mémoire, mais parfois inévitable.
Exemple:
import copy
class Foo(object):
def __init__(self, val):
self.val = val
def __repr__(self):
return str(self.val)
foo = Foo(1)
a = ['foo', foo]
b = a.copy()
c = a[:]
d = list(a)
e = copy.copy(a)
f = copy.deepcopy(a)
# edit orignal list and instance
a.append('baz')
foo.val = 5
print('original: %r\n list.copy(): %r\n slice: %r\n list(): %r\n copy: %r\n deepcopy: %r'
% (a, b, c, d, e, f))
Résultat:
original: ['foo', 5, 'baz']
list.copy(): ['foo', 5]
slice: ['foo', 5]
list(): ['foo', 5]
copy: ['foo', 5]
deepcopy: ['foo', 1]
Félix a déjà fourni une excellente réponse, mais je pensais pouvoir comparer rapidement les différentes méthodes:
copy.deepcopy(old_list)
Copy()
méthode copiant des classes avec deepcopyCopy()
, méthode ne copiant pas les classes (dicts/listes/tuples uniquement)for item in old_list: new_list.append(item)
[i for i in old_list]
(a compréhension de la liste )copy.copy(old_list)
list(old_list)
new_list = []; new_list.extend(old_list)
old_list[:]
( découpage de la liste )Donc, le plus rapide est le découpage de la liste. Sachez toutefois que copy.copy()
, list[:]
et list(list)
, contrairement à copy.deepcopy()
et à la version python, ne copient pas les listes, dictionnaires et instances de classe de la liste. Par conséquent, si les originaux changent, ils seront modifiés. dans la liste copiée aussi et vice versa.
(Voici le script si quelqu'un est intéressé ou veut soulever des questions :)
from copy import deepcopy
class old_class:
def __init__(self):
self.blah = 'blah'
class new_class(object):
def __init__(self):
self.blah = 'blah'
dignore = {str: None, unicode: None, int: None, type(None): None}
def Copy(obj, use_deepcopy=True):
t = type(obj)
if t in (list, Tuple):
if t == Tuple:
# Convert to a list if a Tuple to
# allow assigning to when copying
is_Tuple = True
obj = list(obj)
else:
# Otherwise just do a quick slice copy
obj = obj[:]
is_Tuple = False
# Copy each item recursively
for x in xrange(len(obj)):
if type(obj[x]) in dignore:
continue
obj[x] = Copy(obj[x], use_deepcopy)
if is_Tuple:
# Convert back into a Tuple again
obj = Tuple(obj)
Elif t == dict:
# Use the fast shallow dict copy() method and copy any
# values which aren't immutable (like lists, dicts etc)
obj = obj.copy()
for k in obj:
if type(obj[k]) in dignore:
continue
obj[k] = Copy(obj[k], use_deepcopy)
Elif t in dignore:
# Numeric or string/unicode?
# It's immutable, so ignore it!
pass
Elif use_deepcopy:
obj = deepcopy(obj)
return obj
if __== '__main__':
import copy
from time import time
num_times = 100000
L = [None, 'blah', 1, 543.4532,
['foo'], ('bar',), {'blah': 'blah'},
old_class(), new_class()]
t = time()
for i in xrange(num_times):
Copy(L)
print 'Custom Copy:', time()-t
t = time()
for i in xrange(num_times):
Copy(L, use_deepcopy=False)
print 'Custom Copy Only Copying Lists/Tuples/Dicts (no classes):', time()-t
t = time()
for i in xrange(num_times):
copy.copy(L)
print 'copy.copy:', time()-t
t = time()
for i in xrange(num_times):
copy.deepcopy(L)
print 'copy.deepcopy:', time()-t
t = time()
for i in xrange(num_times):
L[:]
print 'list slicing [:]:', time()-t
t = time()
for i in xrange(num_times):
list(L)
print 'list(L):', time()-t
t = time()
for i in xrange(num_times):
[i for i in L]
print 'list expression(L):', time()-t
t = time()
for i in xrange(num_times):
a = []
a.extend(L)
print 'list extend:', time()-t
t = time()
for i in xrange(num_times):
a = []
for y in L:
a.append(y)
print 'list append:', time()-t
t = time()
for i in xrange(num_times):
a = []
a.extend(i for i in L)
print 'generator expression extend:', time()-t
J'ai on m'a dit que Python 3.3+ ajoute list.copy()
, qui devrait être aussi rapide que le découpage en tranches:
newlist = old_list.copy()
Quelles sont les options pour cloner ou copier une liste en Python?
Dans Python 3, une copie superficielle peut être réalisée avec:
a_copy = a_list.copy()
Dans Python 2 et 3, vous pouvez obtenir une copie superficielle avec une tranche complète de l'original:
a_copy = a_list[:]
Il existe deux manières sémantiques de copier une liste. Une copie superficielle crée une nouvelle liste des mêmes objets, une copie complète crée une nouvelle liste contenant de nouveaux objets équivalents.
Une copie superficielle ne copie que la liste elle-même, qui est un conteneur de références aux objets de la liste. Si les objets contenus eux-mêmes sont mutables et que l'un d'eux est modifié, le changement sera reflété dans les deux listes.
Il existe différentes façons de procéder dans Python 2 et 3. Les méthodes Python 2 fonctionnent également dans Python 3.
Dans Python 2, la manière idiomatique de créer une copie superficielle d'une liste consiste à utiliser une tranche complète de l'original:
a_copy = a_list[:]
Vous pouvez également accomplir la même chose en passant la liste par le constructeur de la liste,
a_copy = list(a_list)
mais utiliser le constructeur est moins efficace:
>>> timeit
>>> l = range(20)
>>> min(timeit.repeat(lambda: l[:]))
0.30504298210144043
>>> min(timeit.repeat(lambda: list(l)))
0.40698814392089844
Dans Python 3, les listes obtiennent la méthode list.copy
:
a_copy = a_list.copy()
Dans Python 3.5:
>>> import timeit
>>> l = list(range(20))
>>> min(timeit.repeat(lambda: l[:]))
0.38448613602668047
>>> min(timeit.repeat(lambda: list(l)))
0.6309100328944623
>>> min(timeit.repeat(lambda: l.copy()))
0.38122922903858125
Utiliser new_list = my_list modifie ensuite new_list à chaque changement de my_list. Pourquoi est-ce?
my_list
est simplement un nom qui pointe vers la liste en mémoire. Lorsque vous dites new_list = my_list
vous ne faites pas de copie, vous ajoutez simplement un autre nom qui pointe en mémoire sur la liste d'origine. Nous pouvons avoir des problèmes similaires lorsque nous faisons des copies de listes.
>>> l = [[], [], []]
>>> l_copy = l[:]
>>> l_copy
[[], [], []]
>>> l_copy[0].append('foo')
>>> l_copy
[['foo'], [], []]
>>> l
[['foo'], [], []]
La liste est juste un tableau de pointeurs sur le contenu, donc une copie superficielle ne fait que copier les pointeurs. Vous avez donc deux listes différentes, mais elles ont le même contenu. Pour faire des copies du contenu, vous avez besoin d'une copie en profondeur.
Pour créer un copie complète d'une liste, sous Python 2 ou 3, utilisez deepcopy
dans le module copy
:
import copy
a_deep_copy = copy.deepcopy(a_list)
Pour démontrer comment cela nous permet de créer de nouvelles sous-listes:
>>> import copy
>>> l
[['foo'], [], []]
>>> l_deep_copy = copy.deepcopy(l)
>>> l_deep_copy[0].pop()
'foo'
>>> l_deep_copy
[[], [], []]
>>> l
[['foo'], [], []]
Nous voyons donc que la liste copiée en profondeur est une liste totalement différente de la liste originale. Vous pouvez lancer votre propre fonction - mais ne le faites pas. Vous êtes susceptible de créer des bogues que vous n'auriez pas autrement en utilisant la fonction deepcopy de la bibliothèque standard.
eval
Vous pouvez voir cela utilisé comme un moyen de copier en profondeur, mais ne le faites pas:
problematic_deep_copy = eval(repr(a_list))
En 64 bits Python 2.7:
>>> import timeit
>>> import copy
>>> l = range(10)
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
27.55826997756958
>>> min(timeit.repeat(lambda: eval(repr(l))))
29.04534101486206
sur 64 bits Python 3.5:
>>> import timeit
>>> import copy
>>> l = list(range(10))
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
16.84255409205798
>>> min(timeit.repeat(lambda: eval(repr(l))))
34.813894678023644
Il existe déjà de nombreuses réponses qui vous expliquent comment faire une copie conforme, mais aucune d’entre elles ne dit pourquoi votre copie originale a échoué.
Python ne stocke pas les valeurs dans les variables; il lie les noms aux objets. Votre assignation d'origine a pris l'objet référencé par my_list
et l'a lié à new_list
également. Quel que soit le nom que vous utilisez, il n’existe toujours qu’une seule liste. Par conséquent, les modifications apportées lorsqu’on le désigne par my_list
seront conservées lorsqu’il sera appelé new_list
. Chacune des autres réponses à cette question vous donne différentes façons de créer un nouvel objet à lier à new_list
.
Chaque élément d'une liste agit comme un nom, en ce sens qu'il se lie non exclusivement à un objet. Une copie superficielle crée une nouvelle liste dont les éléments sont liés aux mêmes objets qu'auparavant.
new_list = list(my_list) # or my_list[:], but I prefer this syntax
# is simply a shorter way of:
new_list = [element for element in my_list]
Pour aller plus loin dans la copie de votre liste, copiez chaque objet auquel fait référence votre liste et liez ces copies d'éléments à une nouvelle liste.
import copy
# each element must have __copy__ defined for this...
new_list = [copy.copy(element) for element in my_list]
Ce n'est pas encore une copie complète, car chaque élément d'une liste peut faire référence à d'autres objets, tout comme la liste est liée à ses éléments. Pour copier de manière récursive chaque élément de la liste, puis chaque autre objet référencé par chaque élément, etc.: effectuez une copie complète.
import copy
# each element must have __deepcopy__ defined for this...
new_list = copy.deepcopy(my_list)
Voir la documentation pour plus d’informations sur les angles de cas dans la copie.
Utilisez thing[:]
>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>>
Le langage utilisé par Python pour cela est newList = oldList[:]
Voici les résultats de chronométrage avec Python 3.6.8. Gardez à l'esprit que ces temps sont relatifs les uns aux autres et non absolus.
Je me suis tenu à ne faire que des copies superficielles, et j'ai également ajouté de nouvelles méthodes qui n'étaient pas possibles en Python2, telles que list.copy()
(le Python3 équivalent en slice ) et deux formes de liste de décompression (*new_list, = list
et new_list = [*list]
):
METHOD TIME TAKEN
b = [*a] 2.75180600000021
b = a * 1 3.50215399999990
b = a[:] 3.78278899999986 # Python2 winner (see above)
b = a.copy() 4.20556500000020 # Python3 "slice equivalent" (see above)
b = []; b.extend(a) 4.68069800000012
b = a[0:len(a)] 6.84498999999959
*b, = a 7.54031799999984
b = list(a) 7.75815899999997
b = [i for i in a] 18.4886440000000
b = copy.copy(a) 18.8254879999999
b = []
for item in a:
b.append(item) 35.4729199999997
Nous pouvons voir que le gagnant de Python2 réussit toujours bien, mais ne dépasse pas beaucoup Python3 list.copy()
, en particulier compte tenu de la lisibilité supérieure de ce dernier.
Dark Horse est la méthode de déballage et de reconditionnement (b = [*a]
), qui est environ 25% plus rapide que le découpage brut, et plus de deux fois plus rapide que l'autre méthode de décompression (*b, = a
).
b = a * 1
fait aussi étonnamment bien.
Notez que ces méthodes donnent pas des résultats équivalents pour toute entrée autre que des listes. Elles fonctionnent toutes pour des objets slicables, quelques-uns fonctionne pour tous les objets itérables, mais seul copy.copy()
fonctionne pour les objets _ plus généraux Python.
Voici le code de test pour les parties intéressées ( Modèle d'ici ):
import timeit
COUNT = 50000000
print("Array duplicating. Tests run", COUNT, "times")
setup = 'a = [0,1,2,3,4,5,6,7,8,9]; import copy'
print("b = list(a)\t\t", timeit.timeit(stmt='b = list(a)', setup=setup, number=COUNT))
print("b = copy.copy(a)\t", timeit.timeit(stmt='b = copy.copy(a)', setup=setup, number=COUNT))
print("b = a.copy()\t\t", timeit.timeit(stmt='b = a.copy()', setup=setup, number=COUNT))
print("b = a[:]\t\t", timeit.timeit(stmt='b = a[:]', setup=setup, number=COUNT))
print("b = a[0:len(a)]\t\t", timeit.timeit(stmt='b = a[0:len(a)]', setup=setup, number=COUNT))
print("*b, = a\t\t\t", timeit.timeit(stmt='*b, = a', setup=setup, number=COUNT))
print("b = []; b.extend(a)\t", timeit.timeit(stmt='b = []; b.extend(a)', setup=setup, number=COUNT))
print("b = []; for item in a: b.append(item)\t", timeit.timeit(stmt='b = []\nfor item in a: b.append(item)', setup=setup, number=COUNT))
print("b = [i for i in a]\t", timeit.timeit(stmt='b = [i for i in a]', setup=setup, number=COUNT))
print("b = [*a]\t\t", timeit.timeit(stmt='b = [*a]', setup=setup, number=COUNT))
print("b = a * 1\t\t", timeit.timeit(stmt='b = a * 1', setup=setup, number=COUNT))
Commençons par le début et Explorer un peu plus profond:
Alors supposons que vous ayez deux listes:
list_1=['01','98']
list_2=[['01','98']]
Et nous devons copier les deux listes, en commençant maintenant par la première liste:
Essayons d'abord par la méthode générale de copie:
copy=list_1
Maintenant, si vous pensez copier la liste_1, vous pouvez vous tromper, vérifions-le:
The id() function shows us that both variables point to the same list object, i.e. they share this object.
print(id(copy))
print(id(list_1))
sortie:
4329485320
4329485320
Surpris? Ok explorons-le:
Donc, comme nous le savons, python ne stocke rien dans une variable, les variables font simplement référence à l'objet et l'objet stocke la valeur. Ici, l'objet est list
mais nous avons créé deux références à ce même objet par deux noms de variables différents. Donc, les deux variables pointent sur le même objet:
alors quand vous faites copy=list_1
ce qu’il fait réellement:
Ici dans l'image list_1 et copy sont deux noms de variable, mais l'objet est le même pour les deux variables qui est list
Donc, si vous essayez de modifier la liste copiée, elle modifiera également la liste d'origine car celle-ci n'en contient qu'une, vous pourrez modifier cette liste, que vous fassiez de la liste copiée ou de la liste d'origine:
copy[0]="modify"
print(copy)
print(list_1)
sortie:
['modify', '98']
['modify', '98']
Donc, il a modifié la liste originale:
Quelle est la solution alors?
Solution :
Passons maintenant à une seconde méthode de copie de la méthode Pythonic:
copy_1=list_1[:]
Maintenant, cette méthode corrige le problème auquel nous faisions face dans le premier numéro, vérifions-le:
print(id(copy_1))
print(id(list_1))
4338792136
4338791432
Donc, comme nous pouvons voir que nos deux listes ont un identifiant différent et que cela signifie que les deux variables pointent vers des objets différents, voici ce qui se passe réellement:
Essayons maintenant de modifier la liste et voyons si nous sommes toujours confrontés au problème précédent:
copy_1[0]="modify"
print(list_1)
print(copy_1)
Sortie:
['01', '98']
['modify', '98']
Comme vous pouvez le constater, cela ne modifie pas la liste d'origine, mais uniquement la liste copiée. Nous sommes donc d'accord.
Alors maintenant, je pense que nous avons terminé? attendez, nous devons aussi copier la deuxième liste imbriquée, alors essayons de manière Pythonic:
copy_2=list_2[:]
Donc list_2 devrait faire référence à un autre objet qui est une copie de list_2 vérifions:
print(id((list_2)),id(copy_2))
nous obtenons la sortie:
4330403592 4330403528
Maintenant, nous pouvons supposer que les deux listes pointent un objet différent, essayons donc de le modifier et voyons qu'il donne ce que nous voulons:
Alors quand on essaye:
copy_2[0][1]="modify"
print(list_2,copy_2)
cela nous donne une sortie:
[['01', 'modify']] [['01', 'modify']]
Maintenant, c'est peu déroutant, nous avons utilisé la méthode Pythonic et nous sommes toujours confrontés au même problème.
comprenons cela:
Alors quand on fait:
copy_2=list_2[:]
nous ne copions actuellement que la liste externe, pas la liste imbriquée, donc la liste imbriquée est le même objet pour les deux listes, vérifions:
print(id(copy_2[0]))
print(id(list_2[0]))
sortie:
4329485832
4329485832
Donc en fait quand on fait copy_2=list_2[:]
c'est ce qui se passe:
Il crée la copie de la liste mais uniquement la copie de la liste externe, pas la copie de la liste imbriquée. La liste imbriquée est identique pour les deux variables. Par conséquent, si vous essayez de modifier la liste imbriquée, elle modifiera également la liste d'origine car l'objet de la liste imbriquée est identique pour les deux. liste imbriquée.
Donc, quelle est la solution?
La solution est deep copy
from copy import deepcopy
deep=deepcopy(list_2)
Alors maintenant, vérifions-le:
print(id((list_2)),id(deep))
sortie:
4322146056 4322148040
les deux identifiants sont différents, vérifions maintenant l'identifiant de la liste imbriquée:
print(id(deep[0]))
print(id(list_2[0]))
sortie:
4322145992
4322145800
Comme vous pouvez voir que les deux identifiants sont différents, nous pouvons donc supposer que les deux listes imbriquées pointent maintenant un objet différent.
Alors, quand vous faites deep=deepcopy(list_2)
ce qui se passe réellement:
Ainsi, les deux listes imbriquées pointent sur un objet différent et ont maintenant une copie séparée de la liste imbriquée.
Essayons maintenant de modifier la liste imbriquée et voyons si elle résout le problème précédent ou non:
alors si nous le faisons:
deep[0][1]="modify"
print(list_2,deep)
sortie:
[['01', '98']] [['01', 'modify']]
Comme vous pouvez le constater, il n'a pas modifié la liste imbriquée d'origine, mais uniquement la liste copiée.
Si vous aimez ma réponse détaillée, faites le moi savoir en la votant, si vous avez le moindre doute sur cette réponse, commentez :)
Tous les autres contributeurs ont donné d'excellentes réponses , qui fonctionnent lorsque vous avez une liste à une seule dimension (mise à niveau), quelle que soit la méthode mentionnée jusqu'à présent, uniquement copy.deepcopy()
fonctionne pour cloner/copier une liste sans que celle-ci ne pointe vers les objets list
imbriqués lorsque vous utilisez des listes multidimensionnelles et imbriquées (liste de listes). Bien que Felix Kling y fasse référence dans sa réponse, le problème est un peu plus complexe et peut-être une solution de contournement utilisant des éléments intégrés qui pourraient s'avérer une alternative plus rapide à deepcopy
.
Alors que new_list = old_list[:]
, copy.copy(old_list)'
et pour Py3k old_list.copy()
fonctionnent pour des listes à un niveau, ils reviennent à pointer sur les objets list
imbriqués dans le old_list
et le new_list
et les modifications apportées à l'un des objets list
se perpétuent dans l'autre.
Comme le soulignaient Aaron Hall et PM 2Ring, utiliser
eval()
n’est pas seulement une mauvaise idée, c’est aussi beaucoup plus lent quecopy.deepcopy()
.Cela signifie que pour les listes multidimensionnelles, la seule option est
copy.deepcopy()
. Cela dit, ce n’est vraiment pas une option, car les performances vont au sud lorsque vous essayez de les utiliser sur un tableau multidimensionnel de taille moyenne. J'ai essayé detimeit
en utilisant un tableau 42x42, pas du jamais vu ou même de cette taille pour les applications de bioinformatique, et j'ai abandonné l'attente d'une réponse et j'ai juste commencé à taper mon édition sur ce post.Il semblerait alors que la seule véritable option consiste à initialiser plusieurs listes et à les travailler de manière indépendante. Si quelqu'un a d'autres suggestions sur la façon de gérer la copie de liste multidimensionnelle, nous vous en serions reconnaissants.
Comme d’autres l’ont déjà dit, il existe des problèmes de performances importants avec le module copy
et copy.deepcopy
pour les listes multidimensionnelles .
Cela me surprend que cela n'ait pas encore été mentionné, alors par souci d'exhaustivité ...
Vous pouvez effectuer le décompactage de liste avec "l'opérateur splat": *
, qui copiera également des éléments de votre liste.
old_list = [1, 2, 3]
new_list = [*old_list]
new_list.append(4)
old_list == [1, 2, 3]
new_list == [1, 2, 3, 4]
L'inconvénient évident de cette méthode est qu'elle n'est disponible que dans Python 3.5+.
En ce qui concerne le timing, cela semble mieux fonctionner que d’autres méthodes courantes.
x = [random.random() for _ in range(1000)]
%timeit a = list(x)
%timeit a = x.copy()
%timeit a = x[:]
%timeit a = [*x]
#: 2.47 µs ± 38.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.47 µs ± 54.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.39 µs ± 58.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.22 µs ± 43.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Notez que dans certains cas, si vous avez défini votre propre classe personnalisée et que vous souhaitez conserver les attributs, vous devez utiliser copy.copy()
ou copy.deepcopy()
plutôt que les alternatives, par exemple dans Python. 3:
import copy
class MyList(list):
pass
lst = MyList([1,2,3])
lst.name = 'custom list'
d = {
'original': lst,
'slicecopy' : lst[:],
'lstcopy' : lst.copy(),
'copycopy': copy.copy(lst),
'deepcopy': copy.deepcopy(lst)
}
for k,v in d.items():
print('lst: {}'.format(k), end=', ')
try:
name = v.name
except AttributeError:
name = 'NA'
print('name: {}'.format(name))
Les sorties:
lst: original, name: custom list
lst: slicecopy, name: NA
lst: lstcopy, name: NA
lst: copycopy, name: custom list
lst: deepcopy, name: custom list
Une approche très simple, indépendante de python, manquait la version dans les réponses déjà données que vous pouvez utiliser la plupart du temps (du moins je le fais):
new_list = my_list * 1 #Solution 1 when you are not using nested lists
Cependant, si my_list contient d’autres conteneurs (par exemple, des listes imbriquées), vous devez utiliser deepcopy comme d’autres suggérés dans les réponses ci-dessus à partir de la bibliothèque de copies. Par exemple:
import copy
new_list = copy.deepcopy(my_list) #Solution 2 when you are using nested lists
.Bonus: Si vous ne voulez pas copier des éléments, utilisez (aussi appelé copie superficielle):
new_list = my_list[:]
Comprenons la différence entre la solution n ° 1 et la solution n ° 2
>>> a = range(5)
>>> b = a*1
>>> a,b
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])
>>> a[2] = 55
>>> a,b
([0, 1, 55, 3, 4], [0, 1, 2, 3, 4])
Comme vous pouvez le constater, la solution n ° 1 fonctionnait parfaitement lorsque nous n’utilisions pas les listes imbriquées. Voyons ce qui se passera lorsque nous appliquerons la solution 1 aux listes imbriquées.
>>> from copy import deepcopy
>>> a = [range(i,i+4) for i in range(3)]
>>> a
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> b = a*1
>>> c = deepcopy(a)
>>> for i in (a, b, c): print i
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> a[2].append('99')
>>> for i in (a, b, c): print i
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]] #Solution#1 didn't work in nested list
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]] #Solution #2 - DeepCopy worked in nested list
new_list = my_list[:]
new_list = my_list
Essayez de comprendre cela. Supposons que my_list se trouve dans la mémoire de tas à l'emplacement X, c'est-à-dire que ma_list pointe vers le X. Maintenant, en assignant new_list = my_list
vous laissez new_list pointer vers le X. C'est ce qu'on appelle une copie superficielle.
Maintenant, si vous assignez new_list = my_list[:]
Vous copiez simplement chaque objet de my_list dans new_list. Ceci est connu comme copie profonde.
L’autre façon de procéder est la suivante:
new_list = list(old_list)
import copy new_list = copy.deepcopy(old_list)
dans python si vous avez défini une valeur de variable et si vous avez réaffecté cette variable à une autre,
la seconde variable n'a qu'une référence au lieu d'une valeur copiée.
>>> l = [1,2,3]
>>> k = l
>>> l[0] = 10
>>> l
[10, 2, 3]
>>> k
[10, 2, 3]
donc si vous changez quelque chose dans l & k, cela reflètera les deux ..
pour copier, utilisez [::] de sorte que l'original n'affectera pas si vous avez fait une affectation.
>>> k = l[::]
>>> k
[10, 2, 3]
>>> l[0] = 100
>>> l
[100, 2, 3]
>>> k
[10, 2, 3]