python - Liste des changements inattendus après affectation. Pourquoi est-ce que je peux l'empêcher

Mots clés : pythonlistreferencecopyclonepython

meilleur 5 Réponses python - Liste des changements inattendus après affectation. Pourquoi est-ce que je peux l'empêcher

vote vote

95

new_list = old_list.copy() 
new_list = old_list[:] 
new_list = list(old_list) 
import copy new_list = copy.copy(old_list) 
import copy new_list = copy.deepcopy(old_list) 
import copy  class Foo(object):     def __init__(self, val):          self.val = val      def __repr__(self):         return 'Foo({!r})'.format(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\nlist.copy(): %r\nslice: %r\nlist(): %r\ncopy: %r\ndeepcopy: %r'       % (a, b, c, d, e, f)) 
original: ['foo', Foo(5), 'baz'] list.copy(): ['foo', Foo(5)] slice: ['foo', Foo(5)] list(): ['foo', Foo(5)] copy: ['foo', Foo(5)] deepcopy: ['foo', Foo(1)] 
vote vote

81

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

80

newlist = old_list.copy() 
vote vote

68

a_copy = a_list.copy() 
a_copy = a_list[:] 
a_copy = a_list[:] 
a_copy = list(a_list) 
>>> timeit >>> l = range(20) >>> min(timeit.repeat(lambda: l[:])) 0.30504298210144043 >>> min(timeit.repeat(lambda: list(l))) 0.40698814392089844 
a_copy = a_list.copy() 
>>> 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 
>>> l = [[], [], []] >>> l_copy = l[:] >>> l_copy [[], [], []] >>> l_copy[0].append('foo') >>> l_copy [['foo'], [], []] >>> l [['foo'], [], []] 
import copy a_deep_copy = copy.deepcopy(a_list) 
>>> import copy >>> l [['foo'], [], []] >>> l_deep_copy = copy.deepcopy(l) >>> l_deep_copy[0].pop() 'foo' >>> l_deep_copy [[], [], []] >>> l [['foo'], [], []] 
problematic_deep_copy = eval(repr(a_list)) 
>>> 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 
>>> 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 
vote vote

57

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] 
import copy   # each element must have __copy__ defined for this... new_list = [copy.copy(element) for element in my_list] 
import copy # each element must have __deepcopy__ defined for this... new_list = copy.deepcopy(my_list) 

Questions similaires