Comment cloner ou copier une liste?

quelles sont les options pour cloner ou copier une liste en Python?

utilisant new_list = my_list modifie alors new_list à chaque fois my_list change.

Pourquoi est-ce?

1780
demandé sur Taryn 2010-04-10 12:49:46

18 réponses

avec new_list = my_list , vous n'avez pas deux listes. La cession ne fait que Copier la référence à la liste, et non à la liste proprement dite, de sorte que new_list et my_list renvoient toutes deux à la même liste après la cession.

pour réellement copier la liste, vous avez diverses 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 couper en tranches:

    new_list = old_list[:]
    

    L'opinion D'Alex Martelli (au moins retour en 2007 ) à ce sujet est, que c'est une syntaxe étrange et il n'a pas de sens de l'utiliser jamais . ;) (À son avis, la suivante est plus lisible).

  • vous pouvez utiliser le construit dans list() fonction:

    new_list = list(old_list)
    
  • vous pouvez utiliser du générique copy.copy() :

    import copy
    new_list = copy.copy(old_list)
    

    c'est un peu plus lent que list() parce qu'il faut d'abord trouver le type de données de old_list .

  • si la liste contient des objets et que vous voulez les copier, utilisez copy.deepcopy() :

    import copy
    new_list = copy.deepcopy(old_list)
    

    évidemment la méthode la plus lente et la plus besoin de 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]
2438
répondu Felix Kling 2018-06-23 15:38:38

Félix a déjà fourni une excellente réponse, mais j'ai pensé que je ferais une comparaison de vitesse des différentes méthodes:

  1. de 10,59 sec (105.9 us/mii) - copy.deepcopy(old_list)
  2. 10.16 sec (101.6 us / itn) - pur python Copy() méthode classes de copie avec deepcopy
  3. 1.488 sec (14.88 us / itn) - Python pur Copy() méthode ne copiant pas les classes (seulement dicts/listes/tuples)
  4. 0,325 sec (3.25 us / itn) - for item in old_list: new_list.append(item)
  5. 0.217 sec (2.17 us / itn) - [i for i in old_list] (a list understanding )
  6. 0.186 sec (1.86 us / itn) - copy.copy(old_list)
  7. 0,075 sec (0,75 us/itn) - list(old_list)
  8. en 0.053 s (0.53 us/itn) - new_list = []; new_list.extend(old_list)
  9. en 0.039 s (0.39 us/itn) - old_list[:] ( liste de découpage )

donc le plus rapide est le listing. Mais sachez que copy.copy() , list[:] et list(list) , contrairement à copy.deepcopy() et à la version python ne copient pas de listes, dictionnaires et instances de classe dans la liste, donc si les originaux changent, ils changeront aussi dans la liste copiée 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 __name__ == '__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

EDIT : ajout de classes et de dicts New-style, old-style aux benchmarks, et rendu la version de python beaucoup plus rapide et ajouté plus de méthodes dont les expressions list et extend() .

461
répondu cryo 2016-08-28 23:29:35

j'ai on m'a dit que Python 3.3+ ajoute list.copy() méthode, qui devrait être aussi rapide que le tranchage:

newlist = old_list.copy()

118
répondu anatoly techtonik 2017-04-05 01:13:42

quelles sont les options pour cloner ou copier une liste en Python?

en Python 3, une copie superficielle peut être faite avec:

a_copy = a_list.copy()

en Python 2 et 3, vous pouvez obtenir une copie peu profonde avec une pleine tranche de l'original:

a_copy = a_list[:]

explication

il y a deux façons sémantiques de copier une liste. Une copie superficielle crée une nouvelle liste des mêmes objets, une copie profonde crée une nouvelle liste contenant de nouveaux objets équivalents.

Superficielle de la liste de copie

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 qu'un est modifié, le changement sera reflété dans les deux listes.

il y a différentes façons de faire ceci en Python 2 et 3. Le Python 2 ways fonctionne aussi en Python 3.

Python 2

en Python 2, la façon idiomatique de faire une copie superficielle d'une liste est avec 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 liste,

a_copy = list(a_list)

mais l'utilisation du constructeur est moins efficace:

>>> timeit
>>> l = range(20)
>>> min(timeit.repeat(lambda: l[:]))
0.30504298210144043
>>> min(timeit.repeat(lambda: list(l)))
0.40698814392089844

Python 3

en Python 3, les listes list.copy méthode:

a_copy = a_list.copy()

En 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

de Faire un autre pointeur n' pas créer une copie

en utilisant new_list = my_list modifie ensuite new_list à chaque fois que my_list change. Pourquoi est-ce?

my_list est juste un nom qui pointe vers la liste actuelle en mémoire. Quand vous dites new_list = my_list vous ne faites pas une copie, vous ajoutez juste un autre nom qui pointe sur cette liste originale en mémoire. 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 vers le contenu, donc une copie superficielle copie juste les pointeurs, et donc vous avez deux listes différentes, mais ils ont le même contenu. Faire des copies du contenu, vous avez besoin d'une copie en profondeur.

Profonde copies

pour faire une copie profonde d'une liste, en Python 2 ou 3, Utilisez deepcopy dans le copy module :

import copy
a_deep_copy = copy.deepcopy(a_list)

pour montrer comment cela nous permet de faire 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'], [], []]

et donc nous voyons que la liste profonde copiée est une liste entièrement différente de l'original. Vous pourriez jouer votre propre rôle, mais ne le faites pas. Vous êtes susceptible de créer des bogues que vous n'auriez pas autrement en utilisant le standard la fonction d'analyse approfondie de la bibliothèque.

Ne pas utiliser eval

vous pouvez voir cela utilisé comme un moyen de la profonde, mais ne le faites pas:

problematic_deep_copy = eval(repr(a_list))
  1. c'est dangereux, surtout si vous évaluez quelque chose d'une source en laquelle vous n'avez pas confiance.
  2. ce n'est pas fiable, si un sous-élément que vous copiez n'a pas de représentation qui peut être évaluée pour reproduire un élément équivalent.
  3. c'est aussi moins performant.

en python 64 bits 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
91
répondu Aaron Hall 2018-01-09 15:33:11

il y a déjà beaucoup de réponses qui vous disent comment faire une copie correcte, mais aucune d'entre elles ne dit Pourquoi votre 'copie' originale a échoué.

Python ne stocke pas de valeurs dans les variables; il lie les noms aux objets. Votre affectation d'origine a pris l'objet référencé par my_list et lié à new_list . Quel que soit le nom que vous utilisez, il n'y a toujours qu'une seule liste, donc les changements apportés lorsque vous faites référence à my_list persisteront lorsque vous faites référence à my_list . new_list . Chacun 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 que chaque élément se lie non exclusivement à un objet. Une copie crée une nouvelle liste dont les éléments se lient aux mêmes objets comme avant.

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 prendre votre liste copiez une étape plus loin, copiez chaque objet auquel votre liste se réfère, 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 profonde, parce que chaque élément d'une liste peut se référer à d'autres objets, tout comme la liste est liée à ses éléments. Pour recursivement copier chaque élément de la liste, puis chaque autre objet auquel se réfère chaque élément, et ainsi de suite: effectuer une copie profonde.

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 cas de coin dans la copie.

42
répondu jack 2018-01-19 16:00:21

new_list = list(old_list)

31
répondu user285176 2010-04-10 09:03:03

utiliser thing[:]

>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>> 
27
répondu Paul Tarjan 2010-04-10 08:53:06

Python est un langage pour le faire, c'est newList = oldList[:]

26
répondu erisco 2010-04-10 08:53:19

tous les autres contributeurs ont donné grand réponses, qui fonctionnent lorsque vous avez une liste de dimension unique (nivelé), cependant des méthodes mentionnées jusqu'à présent, seulement copy.deepcopy() fonctionne pour cloner/copier une liste et ne pas l'avoir pointer vers les objets imbriqués list lorsque vous travaillez avec multidimensionnels, imbriqués listes (liste de listes). Alors que Felix Kling s'y réfère dans sa réponse, Il ya un peu plus à la question et peut-être une solution de contournement en utilisant des built-ins qui pourrait s'avérer une alternative plus rapide à deepcopy .

alors que new_list = old_list[:] , copy.copy(old_list)' et pour Py3k old_list.copy() travaillent pour des listes à un seul niveau, ils reviennent à pointer vers les objets list emboîtés dans le old_list et le new_list , et les changements à l'un des objets list sont perpétués dans l'autre.

Edit: de Nouvelles informations portées à la lumière de

comme a été souligné par les deux Aaron Hall et PM 2Ring utiliser eval() n'est pas seulement une mauvaise idée, il est aussi beaucoup plus lent que copy.deepcopy() .

cela signifie que pour les listes multidimensionnelles, la seule option est copy.deepcopy() . Cela étant dit, ce n'est vraiment pas une option car la performance va bien au sud quand vous essayez de l'utiliser sur un tableau multidimensionnel de taille moyenne. J'ai essayé de timeit en utilisant un tableau 42x42, pas inconnu ou même aussi grand pour les applications bioinformatiques, et j'ai renoncé à attendre une réponse et j'ai juste commencé à taper mon édition à ce post.

il semblerait que la seule vraie option soit alors d'initialiser plusieurs listes et de travailler sur elles indépendamment. Si quelqu'un a d'autres suggestions, pour savoir comment gérer la copie multidimensionnelle de listes, il serait apprécié.

Comme d'autres l'ont déclaré, Il peut être sont importantes problèmes de performance à l'aide du module copy et copy.deepcopy pour les listes multidimensionnelles . essayer de trouver une autre façon de copier la liste multidimensionnelle sans utiliser deepcopy , (je travaillais sur un problème pour un cours qui ne permet que 5 secondes pour l'ensemble de l'algorithme pour exécuter afin de recevoir un crédit), j'ai trouvé un moyen d'utiliser les fonctions intégrées de faire une copie de la liste imbriquée sans les avoir point à un autre ou à l' list objets imbriqués à l'intérieur d'eux. J'ai utilisé eval() et repr() dans l'attribution à faire de la copie de l'ancienne liste dans la nouvelle liste sans la création d'un lien avec l'ancienne liste. Il prend la forme de:

new_list = eval(repr(old_list))

essentiellement ce que cela fait est de faire une représentation de old_list comme une chaîne, puis évalue la chaîne, comme si elle était l'objet de la chaîne représente. Ce faisant, aucun lien vers l'original list objet. Un nouvel objet list est créé et chaque variable pointe vers son propre objet indépendant. Voici un exemple utilisant une liste imbriquée en 2 dimensions.

old_list = [[0 for j in range(y)] for i in range(x)] # initialize (x,y) nested list

# assign a copy of old_list to new list without them pointing to the same list object
new_list = eval(repr(old_list)) 

# make a change to new_list 
for j in range(y):
    for i in range(x):
    new_list[i][j] += 1

si vous vérifiez ensuite le contenu de chaque liste, par exemple une liste de 4 par 3, Python retournera

>>> new_list

[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]

>>> old_list

[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]

bien que ce ne soit probablement pas la façon canonique ou syntaxique correcte de le faire, il semble bien fonctionner. Je n'ai pas testé la performance, mais je vais deviner que eval() et rep() auront moins de temps pour courir que deepcopy .

18
répondu AMR 2017-05-23 11:47:32

contrairement à d'autres langues qui ont variable et valeur , Python a nom et objet .

Cette déclaration:

a = [1,2,3]

signifie donner à la liste (objet) un nom a , et, ceci:

b = a

donne juste le même objet a un nouveau nom b , donc chaque fois que vous faites quelque chose avec a , l'objet change et donc b change.

La seule façon de faire un vraiment copie d'un est de créer un nouvel objet comme d'autres réponses ont déjà dit.

vous pouvez en savoir plus sur ce ici .

13
répondu Statham 2018-04-10 07:06:57

Python 3.6.0 Timings

Voici les résultats de synchronisation en utilisant Python 3.6.0. Gardez à l'esprit que ces temps sont relatifs les uns aux autres, pas absolus.

j'ai continué à ne faire que des copies superficielles, et j'ai aussi ajouté quelques nouvelles méthodes qui n'étaient pas possibles en Python2, comme list.copy() (L'équivalent python3 slice ) et liste de déballage ( *new_list, = list ):

METHOD                  TIME TAKEN
b = a[:]                6.468942025996512   #Python2 winner
b = a.copy()            6.986593422974693   #Python3 "slice equivalent"
b = []; b.extend(a)     7.309216841997113
b = a[0:len(a)]         10.916740721993847
*b, = a                 11.046738261007704
b = list(a)             11.761539687984623
b = [i for i in a]      24.66165203397395
b = copy.copy(a)        30.853400873980718
b = []
for item in a:
  b.append(item)        48.19176080400939

nous peut voir le vieux gagnant sort toujours sur le dessus, mais pas vraiment par une quantité énorme, compte tenu de la lisibilité accrue de L'approche Python3 list.copy() .

notez que ces méthodes font et non résultats équivalents de sortie pour toute entrée autre que les listes. ils travaillent tous pour des objets tranchables, quelques-uns travaillent pour n'importe quel itérable, mais seulement copy.copy() fonctionne pour n'importe quel objet Python.


voici le code d'essai 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\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", timeit.timeit(stmt='b = a[0:len(a)]', setup=setup, number=COUNT))
print("*b, = a\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 = []\nfor 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))
12
répondu River 2017-04-05 01:07:39

commençons par le début et explorons-le un peu profondément:

supposons donc que vous ayez deux listes:

list_1=['01','98']
list_2=[['01','98']]

et nous devons copier les deux listes, maintenant à partir de la première liste:

donc d'abord essayons par méthode générale de la copie:

copy=list_1

maintenant si vous pensez copier copié la list_1 alors vous pouvez vous tromper, vérifions:

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 allons l'explorer:

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 objet est list mais nous avons créé deux références à ce même objet par deux noms de variables différentes. Donc les deux variables pointent vers le même objet :

ainsi quand vous faites copy=list_1 ce qu'il fait réellement:

enter image description here

ici dans l'image list_1 et copy sont deux noms de variables mais l'objet est le même pour les deux variables qui est list

donc si vous essayez de modifier la liste copiée alors il va modifier la liste originale aussi parce que la liste est un seul là, vous allez modifier cette liste non matière que vous faites à partir de la liste copiée ou de la liste originale:

copy[0]="modify"

print(copy)
print(list_1)

sortie:

['modify', '98']
['modify', '98']

de sorte qu'il a modifié la liste originale:

Quelle est la solution alors?

Solution:

passons maintenant à une deuxième méthode pythonique de liste de copie:

copy_1=list_1[:]

maintenant cette méthode fixer la chose ce que nous

print(id(copy_1))
print(id(list_1))

4338792136
4338791432

donc, comme nous pouvons voir que nos deux listes ont des id différents et cela signifie que les deux variables pointent vers des objets différents donc ce qui se passe réellement ici est:

enter image description here

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 voir, il ne modifie pas la liste originale, il a seulement modifié la liste copiée, donc nous sommes ok avec elle.

donc maintenant je pense que nous avons fini? attendez, nous devons aussi copier la deuxième liste imbriquée, alors essayons pythonic way:

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 alors essayons de le modifier et voyons s'il donne ce que nous voulons:

ainsi quand nous essayons:

copy_2[0][1]="modify"

print(list_2,copy_2)

il nous donne de sortie:

[['01', 'modify']] [['01', 'modify']]

maintenant, c'est peu de confusion nous avons utilisé la manière pythonique et encore, nous sommes confrontés au même problème.

nous allons comprendre:

donc quand nous faisons:

copy_2=list_2[:]

nous sommes en train de copier la liste extérieure seulement, 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 nous faisons copy_2=list_2[:] c'est ce qui se passe:

enter image description here

il crée la copie de la liste mais seulement l'extérieur la copie de liste, pas la copie de liste imbriquée, la liste imbriquée est la même pour les deux variables donc si vous essayez de modifier la liste imbriquée, alors elle modifiera la liste originale aussi parce que l'objet liste imbriquée est le même pour les deux listes imbriquées.

Quelle est donc la solution?

la Solution est deep copy

from copy import deepcopy
deep=deepcopy(list_2)

alors maintenant vérifions:

print(id((list_2)),id(deep))

sortie:

4322146056 4322148040

les deux id sont différents , maintenant vérifions l'id de liste imbriqué:

print(id(deep[0]))
print(id(list_2[0]))

sortie:

4322145992
4322145800

comme vous pouvez le voir les deux id sont différents de sorte que nous pouvons supposer que les deux listes imbriquées pointent un objet différent maintenant.

ainsi quand vous faites deep=deepcopy(list_2) ce qui se passe réellement:

enter image description here

donc les deux listes imbriquées pointent objet différent et ils ont maintenant une copie de la liste emboîtée.

essayons maintenant de modifier la liste imbriquée et voyons si elle a résolu le problème précédent ou pas:

donc si nous le faisons:

deep[0][1]="modify"
print(list_2,deep)

sortie:

[['01', '98']] [['01', 'modify']]

comme vous pouvez le voir il n'a pas modifié la liste imbriquée originale , il a seulement modifié la liste copiée.

Si vous aimez ma réponse , laissez-moi savoir par upvoting il , si vous avez un doute realted cette réponse, commenter:)

12
répondu Ayodhyankit Paul 2017-11-13 07:04:17

cela me surprend que cela n'ait pas encore été mentionné, donc par souci d'exhaustivité...

vous pouvez effectuer le déballage de liste avec l '"opérateur splat": * , qui va également copier 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 qu'en Python 3.5+.

Timing sage cependant, cela semble mieux fonctionner que d'autres méthodes communes.

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)
7
répondu SCB 2018-02-26 02:33:47

Je ne sais pas si c'est encore le cas, mais le même comportement vaut pour les dictionnaires. Regardez cet exemple.

a = {'par' : [1,21,3], 'sar' : [5,6,8]}
b = a
c = a.copy()
a['har'] = [1,2,3]

a
Out[14]: {'har': [1, 2, 3], 'par': [1, 21, 3], 'sar': [5, 6, 8]}

b
Out[15]: {'har': [1, 2, 3], 'par': [1, 21, 3], 'sar': [5, 6, 8]}

c
Out[16]: {'par': [1, 21, 3], 'sar': [5, 6, 8]}
4
répondu Bobesh 2017-09-08 08:39:37

notez qu'il y a des cas où si vous avez défini votre propre classe personnalisée et que vous voulez conserver les attributs, vous devez utiliser copy.copy() ou copy.deepcopy() plutôt que les alternatives, par exemple en 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))

sorties:

lst: original, name: custom list
lst: slicecopy, name: NA
lst: lstcopy, name: NA
lst: copycopy, name: custom list
lst: deepcopy, name: custom list
3
répondu Chris_Rands 2018-05-16 14:31:22
new_list = my_list[:]

new_list = my_list Essayer de comprendre cela. Disons que my_list est dans la mémoire tas à l'emplacement X, c'est-à-dire que my_list pointe vers le X. maintenant, en assignant new_list = my_list , vous permettez à new_list de 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 à new_list. Ceci est connu en tant que copie en Profondeur.

L'autre façon que vous pouvez faire ceci sont:

  • new_list = list(old_list)
  • import copy new_list = copy.deepcopy(old_list)
2
répondu Ravi Shankar 2017-06-26 21:03:30

une approche très simple indépendante de la version python manquait dans les réponses déjà données que vous pouvez utiliser la plupart du temps (au 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: listes imbriquées) vous devez utiliser deepcopy comme les autres suggérés dans les réponses ci-dessus de la bibliothèque de copie. 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 d'éléments utiliser (alias shallow copie):

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 voir la Solution n ° 1 a fonctionné parfaitement lorsque nous n'utilisions pas les listes imbriquées. Vérifions ce qui se passera lorsque nous appliquerons la solution n ° 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
2
répondu jainashish 2017-11-01 08:08:25

vous pouvez utiliser bulit dans la fonction list ():

newlist=list(oldlist)

je pense que ce code vous aidera.

2
répondu Akash Nayak 2017-11-15 13:17:33