我理解给定一个可迭代的
>>> it = [1, 2, 3, 4, 5, 6, 7, 8, 9]
我可以把它变成一个列表并在任意点切掉两端,例如
>>> it[1:-2]
[2, 3, 4, 5, 6, 7]
或用
反转>>> it[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1]
或将两者结合起来
>>> it[1:-2][::-1]
[7, 6, 5, 4, 3, 2]
但是,尝试在一次操作中完成此操作会产生一些令我困惑的结果:
>>> it[1:-2:-1]
[]
>>>> it[-1:2:-1]
[9, 8, 7, 6, 5, 4]
>>>> it[-2:1:-1]
[8, 7, 6, 5, 4, 3]
经过多次试验和错误,我能得到我想要的东西:
>>> it[-3:0:-1]
[7, 6, 5, 4, 3, 2]
这让我头痛(并且无法帮助我的代码的读者):
>>> it[-3:0:-1] == it[1:-2][::-1]
True
我怎么能理解这个?我是否应该在思考这些事情?
FWYW,我的代码对迭代进行了大量的截断,反转和处理,我正在寻找比list(reversed(it[1:-2]))
更快更清晰(是的,不要笑)的东西。
答案 0 :(得分:7)
这是因为在像 -
这样的切片中list[start:stop:step]
start
包含 ,结果列表从索引start
开始。
stop
独占 ,即结果列表仅包含stop - 1
之前的元素(而不是stop
处的元素)。
因此,对于您的案例it[1:-2]
- 1
包含,这意味着切片结果从索引1
开始,而-2
是独占,因此切片索引的最后一个元素来自索引-3
。
因此,如果你想要颠倒它,你必须做it[-3:0:-1]
- 只有那时-3
将被包含在切片结果中,并且切片结果将达到1
索引。
答案 1 :(得分:6)
您需要了解的重要事项是
开始将包含在切片
停止将 NOT 包含在切片
如果要向后切片,则步长值应为负值。
基本上,您指定的范围是半开(半闭)范围。
如果你说it[-3:0:-1]
实际上是从后面的第三个元素开始,直到我们到达0
(不包括零),则一次向后移动一个元素。
>>> it[-3:0:-1]
[7, 6, 5, 4, 3, 2]
相反,您可以像这样实现起始值
>>> it[len(it)-3 : 0 : -1]
[7, 6, 5, 4, 3, 2]
答案 2 :(得分:2)
我认为其他两个答案消除了slicing
的使用歧义,并更清晰地了解其参数的工作原理。
但是,由于您的问题还涉及 可读性 - 我们不要忘记, 是一个重要因素,特别是在Python中 - 我想指出如何通过将slice()
个对象分配给变量来稍微改进它,从而删除所有那些硬编码的:
个分隔数字。
您的截断和反向切片对象也可以使用含义名称进行编码:
rev_slice = slice(-3, 0, -1)
在其他一些配置文件中。然后你可以在切片操作中使用它的命名荣耀,使这个有点在眼睛上更容易:
it[rev_slice] # [7, 6, 5, 4, 3, 2]
这可能是一个微不足道的事情,但我认为这可能是值得的。
答案 3 :(得分:2)
为什么不创建一个可读性函数:
def listify(it, start=0, stop=None, rev=False):
if stop is None:
the_list = it[start:]
else:
the_list = it[start:stop]
if rev:
return the_list[::-1]
else:
return the_list
listify(it, start=1, stop=-2) # [2, 3, 4, 5, 6, 7]
listify(it, start=1, stop=-2, rev=True) # [7, 6, 5, 4, 3, 2]
答案 4 :(得分:0)
直观地理解Python切片语法的一个好方法是查看它如何映射到相应的C for
循环。
像
这样的切片x[a:b:c]
为您提供与
相同的元素for (int i = a; i < b; i += c) {
...
}
特殊情况只是默认值:
a
默认为0 b
默认为len(x)
c
默认为1 另外还有一个特例:
c
为否定,则a
和b
会被换掉,<
会被转换为>