了解列表切片中的负面步骤

jar*_*arm 5 python list slice negative-number

我试图了解以下行为,并欢迎任何参考(尤其是官方文档)或评论。

让我们考虑一个列表:

>>> x = [1,2,3,4,5,6]
Run Code Online (Sandbox Code Playgroud)

这按预期工作

>>> x[-1:-4:-1] 
[6, 5, 4]
Run Code Online (Sandbox Code Playgroud)

但我很惊讶以下是空的:

>>>  x[0:-4:-1] 
[]
Run Code Online (Sandbox Code Playgroud)

因此,我很惊讶以下不是空的

>>> x[0:-len(x)-1:-1]
> [1]
Run Code Online (Sandbox Code Playgroud)

特别是考虑到

>>> x[0:-len(x):-1] 
[]
Run Code Online (Sandbox Code Playgroud)

还有那个

>>> x[0:-len(x)-1] 
[]
Run Code Online (Sandbox Code Playgroud)

是空的。

jar*_*arm 6

有人向我指出了参考实现(给匿名捐助者的帽子),并发现从那里理解行为相当简单。完整地说,恕我直言,这种行为并不直观,但它仍然定义良好并且与参考实现相匹配。

有两个相关的 CPython 文件,即描述list_subscriptPySlice_AdjustIndices 的文件。当从列表中检索切片时(如本例所示),将调用list_subscript 。它调用PySlice_GetIndicesEx,后者又调用PySlice_AdjustIndices。现在PySlice_AdjustIndices包含简单的 if/then 语句,用于调整索引。最后它返回切片的长度。对于我们的例子,这些行

if (*stop < 0) {
    *stop += length;
    if (*stop < 0) {
        *stop = (step < 0) ? -1 : 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

有趣的是,PySlice_AdjustIndices中有以下注释:

/* this is harder to get right than you might think */
Run Code Online (Sandbox Code Playgroud)

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


sch*_*ggl 5

事实是

> x[-1:-4:-1] 
[6, 5, 4]
> x[0:-4:-1] 
[]
Run Code Online (Sandbox Code Playgroud)

不应该让你感到惊讶!很明显,您可以倒序将列表从最后一个元素切片到倒数第四个元素,但不能从第一个元素开始。

x[0:i:-1]
Run Code Online (Sandbox Code Playgroud)

i必须是< -len(x)为了解决到索引< 0为结果含有的元素。slice 的语法很简单:

x[start:end:step]
Run Code Online (Sandbox Code Playgroud)

意味着,切片从start(here :) 开始0 end(或任何负数引用的索引)之前结束end-len(x)解析为0,因此从长度为开始到0结束的切片不包含任何元素。,但是,将解析为实际的,从而产生从 开始的长度切片。00-len(x)-1-110

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

> l[2::-1]
[3, 2, 1]
> l[0::-1]
[1]
Run Code Online (Sandbox Code Playgroud)