python 列表复制:old[:] 和 list(old) 有区别吗?
old = [1, 2, 3]
这两行代码有什么区别吗?如果有的话,是什么?
new = old[:]
new = list(old)
更新 我之前已经接受了ubershmekel的回答,但后来我了解到一个有趣的事实:对于小列表(10个元素),使用[:]
会更快,而对于大列表(100000个元素),使用list()
会更快。
~$ python -S -mtimeit -s "a = list(range(10))" "a[:]"
1000000 loops, best of 3: 0.198 usec per loop
~$ python -S -mtimeit -s "a = list(range(10))" "list(a)"
1000000 loops, best of 3: 0.453 usec per loop
~$ python -S -mtimeit -s "a = list(range(100000))" "a[:]"
1000 loops, best of 3: 675 usec per loop
~$ python -S -mtimeit -s "a = list(range(100000))" "list(a)"
1000 loops, best of 3: 664 usec per loop
6 个回答
1
在你给出的例子中,没什么区别:两者都会产生一个全新的 list
对象,里面的元素是一样的。
一般来说:
new = old[:]
只适用于支持切片的对象,new
的类型和old
是一样的。new = list(old)
可以用于任何可迭代的对象,new
会变成一个list
。
6
如果 old 不是一个列表,那么 old[:] 会把 old 中的所有元素放在和 old 一样类型的容器里(可能是元组或者字符串),而 list(old) 则会把这些元素放到一个列表里。
举个例子,如果 old 是字符串 'foo',那么 old[:] 还是字符串 'foo',而 list(old) 就变成了列表 ['f', 'o', 'o']。
4
是的,这里有一点小区别。最近在/r/python上有个讨论,讨论的原因是这篇博客提到了一些可读性方面的差异,比如说用[:]
的方式在处理生成器时不太适用,而且它会保持和原来一样的类型。
从技术上讲,你得到的结果是一样的——一个全新的列表,但它仍然指向原来的对象。你可以选择你更喜欢的方式(不过[:]
稍微快一点)。我个人觉得那篇博客说的list(old)
更容易理解。
关于具体的区别,在Python 3.2中:
>>> import dis
>>> def colon(x):
... return x[:]
...
>>> def new_list(x):
... return list(x)
...
>>>
>>> dis.dis(colon)
2 0 LOAD_FAST 0 (x)
3 LOAD_CONST 0 (None)
6 LOAD_CONST 0 (None)
9 BUILD_SLICE 2
12 BINARY_SUBSCR
13 RETURN_VALUE
>>> dis.dis(new_list)
2 0 LOAD_GLOBAL 0 (list)
3 LOAD_FAST 0 (x)
6 CALL_FUNCTION 1
9 RETURN_VALUE
>>>
至于为什么list(old)
会慢一点,我认为是因为切片机制不需要在列表构造函数上执行“LOAD_GLOBAL”和“CALL_FUNCTION”,整个操作都是在C语言中处理的。