[Python] リストのコピー

問題

a = [1, 4, 7, 11]
b = list(a)
a[3] =10
print(b[3])

答え

11 が出力されます。

Pythonでは、リストは代入すると同じリストを指します。

>>> a = [1, 4, 7, 11]
>>> b = a
>>> a is b
True
>>> id(a)
1927677055240
>>> id(b)
1927677055240

Pythonでのリストのコピー

コピーをするためにはいくつか方法があります。

スタックオーバーフローの以下の記事が大変良いです。

How to clone or copy a list?

ちなみに、数ある方法の中で、スライスが一番スピードが速いようです。

10.59 sec (105.9us/itn) – copy.deepcopy(old_list)
10.16 sec (101.6us/itn) – pure python Copy() method copying classes with deepcopy
1.488 sec (14.88us/itn) – pure python Copy() method not copying classes (only dicts/lists/tuples)
0.325 sec (3.25us/itn) – for item in old_list: new_list.append(item)
0.217 sec (2.17us/itn) – [i for i in old_list] (a list comprehension)
0.186 sec (1.86us/itn) – copy.copy(old_list)
0.075 sec (0.75us/itn) – list(old_list)
0.053 sec (0.53us/itn) – new_list = []; new_list.extend(old_list)
0.039 sec (0.39us/itn) – old_list[:] (list slicing)

https://stackoverflow.com/a/2612990

copyモジュール

>>> import copy
>>> a = [1, 4, 7, 11]
>>> b = copy.copy(a)
>>> print(b)
[1, 4, 7, 11]
>>> a is b
False

もし 、リストの中にオブジェクトがある場合、その中のオブジェクトもコピーするためには、copy.deepcopy()を使います。この場合はdeepcopyの一択で、他の方法は使えません。

copy — 浅いコピーおよび深いコピー操作

スライス

>>> a = [1, 4, 7, 11]
>>> b = a[:]
>>> print(b)
[1, 4, 7, 11]
>>> a is b
False

list()

>>> a = [1, 4, 7, 11]
>>> b = list(a)
>>> print(b)
[1, 4, 7, 11]
>>> a is b
False

これは、[[1, 4, 7, 11]]を返すと思っていたけど、違ったんですね。

class list([iterable])
Return a list whose items are the same and in the same order as iterable’s items. iterable may be either a sequence, a container that supports iteration, or an iterator object. If iterable is already a list, a copy is made and returned, similar to iterable[:]. For instance, list('abc') returns ['a', 'b', 'c'] and list( (1, 2, 3) ) returns [1, 2, 3]. If no argument is given, returns a new empty list, [].

https://docs.python.org/2/library/functions.html#func-list

イテラブルなものが既にリストであるなら、イテラブル[:]と同じように、コピーしてそのコピーを返します。