我们可以(浅)复制a list
使用[:]
:
l = [1, 2, 3] z1 = l[:]
我们也可以(浅)复制它[::]
:
z2 = l[::]
现在z1 == z2
将True
.在阅读了Explain Python的切片表示法中的答案之后,我理解这些切片是如何工作的.
但是,我的问题是,这两者内部有什么区别吗?复制中的一个比另一个更有效,还是做同样的事情?
它们之间绝对没有区别,至少在Python 3中是这样.dis.dis
如果您愿意,可以使用以下方法检查为每个字节码生成的字节码:
l = [1, 2, 3, 4]
发出的字节码l[:]
:
from dis import dis dis('l[:]') 1 0 LOAD_NAME 0 (l) 3 LOAD_CONST 0 (None) 6 LOAD_CONST 0 (None) 9 BUILD_SLICE 2 12 BINARY_SUBSCR 13 RETURN_VALUE
而,发出的字节码为l[::]
:
dis('l[::]') 1 0 LOAD_NAME 0 (l) 3 LOAD_CONST 0 (None) 6 LOAD_CONST 0 (None) 9 BUILD_SLICE 2 12 BINARY_SUBSCR 13 RETURN_VALUE
你可以看到,它们完全一样.两者都加载一些None
(两个LOAD_CONSTS
)的值,start
并stop
用于构建切片(BUILD_SLICE
)并应用它.None
s为这些默认为在文档中阐明slices
在标准型层次结构:
特殊的只读属性:
start
是lower
绑定的;stop
是上限;step
是step
价值;None
如果省略则各自.这些属性可以是任何类型.
使用[:]
,它是更少的击键.
实际上有趣的是,在Python中2.x
,生成的字节代码是不同的,并且由于较少的命令l[:]
可能会稍微提高性能:
>>> def foo(): ... l[:] ... >>> dis(foo) 2 0 LOAD_GLOBAL 0 (l) 3 SLICE+0 4 POP_TOP 5 LOAD_CONST 0 (None) 8 RETURN_VALUE
同时,为l[::]
:
>>> def foo2(): ... l[::] ... >>> dis(foo2) 2 0 LOAD_GLOBAL 0 (l) 3 LOAD_CONST 0 (None) 6 LOAD_CONST 0 (None) 9 LOAD_CONST 0 (None) 12 BUILD_SLICE 3 15 BINARY_SUBSCR 16 POP_TOP 17 LOAD_CONST 0 (None) 20 RETURN_VALUE
即使我没有计时这些(我不会,差异应该很小),似乎由于需要的指令较少,l[:]
可能会略微好一些.
这种相似性当然不仅仅存在于列表中 ; 它适用于Python中的所有序列:
# Note: the Bytecode class exists in Py > 3.4 >>> from dis import Bytecode >>> >>> Bytecode('(1, 2, 3)[:]').dis() == Bytecode('(1, 2, 3)[::]').dis() True >>> Bytecode('"string"[:]').dis() == Bytecode('"string"[::]').dis() True
其他人同样如此.