# python 'list' object - 如何克隆或複制列表？

1. 10.59秒（105.9us / itn） - `copy.deepcopy(old_list)`
2. 10.16秒（101.6us / itn） - 使用deepcopy複製類的純python `Copy()`方法
3. 1.488秒（14.88us / itn） - 純python `Copy()`方法不復制類（只有字符串/列表/元組）
4. 0.325秒（3.25us / itn） - `for item in old_list: new_list.append(item)`
5. 0.217秒（2.17us / itn） - `[i for i in old_list]`列表理解
6. 0.186秒（1.86us / itn） - `copy.copy(old_list)`
7. 0.075秒（0.75us / itn） - `list(old_list)`
8. 0.053秒（0.53us / itn） - `new_list = []; new_list.extend(old_list)` `new_list = []; new_list.extend(old_list)`
9. 0.039秒（0.39us / itn） - `old_list[:]`列表切片

（如果任何人有興趣或想提出任何問題，這裡是腳本:)

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

has no attribute

# 在Python中克隆或複制列表有哪些選項？

``````a_copy = a_list.copy()
``````

``````a_copy = a_list[:]
``````

## 淺列表複製

### Python 2

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

### Python 3

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

## 製作另一個指針不會創建副本

`my_list`只是一個指向內存中實際列表的名稱。 當你說`new_list = my_list`你並沒有創建一個副本，你只需添加另一個名字，指向內存中的原始列表。 當我們製作副本時，我們可能會遇到類似的問題。

``````>>> 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'], [], []]
``````

## 不要使用`eval`

``````problematic_deep_copy = eval(repr(a_list))
``````
1. 這很危險，特別是如果你從一個你不信任的來源評估某些東西的話。
2. 這是不可靠的，如果你正在復制的子元素沒有可以被評估以再現等同元素的表示。
3. 它的性能也較差。

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

`new_list = list(old_list)`

Python的成語是`newList = oldList[:]`

## Python 3.6.0定時

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

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

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

``````copy=list_1
``````

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

``````4329485320
4329485320
``````

``````copy[0]="modify"

print(copy)
print(list_1)
``````

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

``````copy_1=list_1[:]
``````

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

4338792136
4338791432
``````

``````copy_1[0]="modify"

print(list_1)
print(copy_1)
``````

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

``````copy_2=list_2[:]
``````

``````print(id((list_2)),id(copy_2))
``````

``````4330403592 4330403528
``````

``````copy_2[0][1]="modify"

print(list_2,copy_2)
``````

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

``````copy_2=list_2[:]
``````

``````print(id(copy_2[0]))
print(id(list_2[0]))
``````

``````4329485832
4329485832
``````

``````from copy import deepcopy
deep=deepcopy(list_2)
``````

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

``````4322146056 4322148040
``````

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

``````4322145992
4322145800
``````

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

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

``````old_list = [1, 2, 3]

new_list = [*old_list]

new_list.append(4)
old_list == [1, 2, 3]
new_list == [1, 2, 3, 4]
``````

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

``````new_list = my_list * 1       #Solution 1 when you are not using nested lists
``````

``````import copy
new_list = copy.deepcopy(my_list)   #Solution 2 when you are using nested lists
``````

``````new_list = my_list[:]
``````

``````>>> 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])
``````

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

### Tags

python   list   copy   clone