Python的切片界限和" stride"之间的神秘互动

时间:2015-10-26 17:41:41

标签: python list python-2.7 slice

我理解给定一个可迭代的

>>> 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]))更快更清晰(是的,不要笑)的东西。

5 个答案:

答案 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为否定,则ab会被换掉,<会被转换为>