web-dev-qa-db-fra.com

Comment cloner ou copier une liste?

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?

2189
aF.

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]
2919
Felix Kling

Félix a déjà fourni une excellente réponse, mais je pensais pouvoir comparer rapidement les différentes méthodes:

  1. 10.59 sec (105.9us/itn) - copy.deepcopy(old_list)
  2. 10.16 sec (101.6us/itn) - pure python Copy() méthode copiant des classes avec deepcopy
  3. 1.488 sec (14.88us/itn) - pure python Copy(), méthode ne copiant pas les classes (dicts/listes/tuples uniquement)
  4. 0.325 sec (3.25us/itn) - for item in old_list: new_list.append(item)
  5. 0.217 sec (2.17us/itn) - [i for i in old_list] (a compréhension de la liste )
  6. 0.186 sec (1.86us/itn) - copy.copy(old_list)
  7. 0.075 sec (0.75us/itn) - list(old_list)
  8. 0.053 sec (0.53us/itn) - new_list = []; new_list.extend(old_list)
  9. 0.039 sec (0.39us/itn) - 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
545
cryo

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()

135
anatoly techtonik

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[:]

Explication

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.

Copie de la liste peu profonde

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.

Python 2

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

Python 3

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

Faire un autre pointeur fait not ​​faire une copie

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.

Copies profondes

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.

N'utilisez pas 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))
  1. C'est dangereux, surtout si vous évaluez quelque chose provenant 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 puisse être évaluée pour reproduire un élément équivalent.
  3. C'est aussi moins performant.

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
120
Aaron Hall

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.

51
jack

Utilisez thing[:]

>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>> 
34
Paul Tarjan

Le langage utilisé par Python pour cela est newList = oldList[:]

32
erisco

Python 3.6 Timings

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))
22
River

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:

enter image description here

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:

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

enter image description here

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:

enter image description here

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 :)

19
Aaditya Ura

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.

Edit: Nouvelles informations mises en lumière

Comme le soulignaient Aaron Hall et PM 2Ring, utiliser eval() n’est pas seulement une mauvaise idée, c’est aussi beaucoup plus lent que copy.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é de timeit 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 .

18
AMR

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)
11
SCB

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
6
Chris_Rands

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
5
jainashish
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)
3
Ravi Shankar

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]
0