关于python:理解列表切片中的负面步骤

Understanding negative steps in list slicing

我试图理解以下行为,并欢迎任何参考(特别是官方文件)或评论。

让我们考虑一个列表:

1
>>> x = [1,2,3,4,5,6]

按预期工作

1
2
>>> x[-1:-4:-1]
[6, 5, 4]

但我很惊讶以下内容是空的:

1
2
>>>  x[0:-4:-1]
[]

因此,我很惊讶以下内容并非空的

1
2
>>> x[0:-len(x)-1:-1]
> [1]

尤其是考虑到这一点

1
2
>>> x[0:-len(x):-1]
[]

而且

1
2
>>> x[0:-len(x)-1]
[]

是空的。


事实是

1
2
3
4
> x[-1:-4:-1]
[6, 5, 4]
> x[0:-4:-1]
[]

不应该让你吃惊!很明显,您可以向后分步骤从最后一个元素到最后一个元素的第四个,但不能从第一个元素分割列表。

1
x[0:i:-1]

i必须是< -len(x),以便解析为索引< 0,以便结果包含元素。slice的语法就是这样简单的:

1
x[start:end:step]

意思是,切片开始于start(此处:0,结束于end(或任何负end引用的索引)。-len(x)解析为0,因此从0开始到0结束的一个切片的长度为0,不包含元素。然而,-len(x)-1将解析为实际的-1,导致从0开始的一段长度1

end留空在后向切片中更直观地理解为:

1
2
3
4
> l[2::-1]
[3, 2, 1]
> l[0::-1]
[1]


我提到了参考实现(hattip指向匿名捐助者),发现从中理解行为是相当简单的。完整地说,imho这个行为是非指导性的,但是它仍然被很好地定义并与引用实现相匹配。

两个cpython文件是相关的,即描述list_subscript和pyslice_adjustindices的文件。在这种情况下,从列表中检索切片时,将调用列表下标。它称为pyslice_getindicex,而pyslice_又称为adjustindices。现在pyslice_adjustindices包含简单的if/then语句,用于调整索引。最后返回切片的长度。对我们来说,这些线条

1
2
3
4
5
6
if (*stop < 0) {
    *stop += length;
    if (*stop < 0) {
        *stop = (step < 0) ? -1 : 0;
    }
}

具有特殊的相关性。调整后,x[0:-len(x)-1:-1]变为x[0:-1:-1],返回长度1。但是,当通过x[0:-1:-1]进行调整时,它变成长度为0的x[0:len(x)-1:-1]。换句话说,在这种情况下,f(x) != f(f(x))

有趣的是注意到pyslice_adjustindices中有以下注释:

1
/* this is harder to get right than you might think */

最后,请注意,在python文档中没有描述有关情况的处理。


1
x[0:-4:-1]

使用-1步从0转到2?