了解列表切片中的负步骤
Understanding negative steps in list slicing
我正在尝试理解以下行为,欢迎任何参考(尤其是官方文档)或评论。
让我们考虑一个列表:
>>> x = [1,2,3,4,5,6]
这按预期工作
>>> x[-1:-4:-1]
[6, 5, 4]
但我很惊讶下面是空的:
>>> x[0:-4:-1]
[]
因此,我很惊讶下面不是空的
>>> x[0:-len(x)-1:-1]
> [1]
特别是考虑到
>>> x[0:-len(x):-1]
[]
还有那个
>>> x[0:-len(x)-1]
[]
为空。
事实
> x[-1:-4:-1]
[6, 5, 4]
> x[0:-4:-1]
[]
应该不会让你吃惊!很明显,您可以在向后的步骤中将列表从最后一个元素切片到 fourth-last 元素,但不能从第一个元素切片。
在
x[0:i:-1]
i
必须是 < -len(x)
才能解析为索引 < 0
,以便结果包含元素。
slice 的语法很简单:
x[start:end:step]
意味着,切片开始于 start
(此处:0
)并结束于 before end
(或任何引用的索引)否定 end
)。 -len(x)
解析为 0
,因此从 0
开始到 0
结束的切片长度为 0
,不包含任何元素。然而,-len(x)-1
将解析为实际的 -1
,导致长度为 1
的切片从 0
.
开始
让end
在后向切片中留空更直观地理解:
> l[2::-1]
[3, 2, 1]
> l[0::-1]
[1]
我被指向了参考实现(hattip to the Anonymous Benefactor),发现从那里理解行为是相当简单的。完整地说,恕我直言,这种行为不直观,但它定义明确并且与参考实现相匹配。
有两个 CPython 文件相关,即描述 list_subscript and PySlice_AdjustIndices 的文件。在这种情况下从列表中检索切片时,将调用 list_subscript。它调用 PySlice_GetIndicesEx,后者又调用 PySlice_AdjustIndices。
现在 PySlice_AdjustIndices 包含简单的 if/then 语句,用于调整索引。最后它 returns 切片的长度。对于我们的例子,行
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]
传给adjust时,就变成了长度为0的x[0:len(x)-1:-1]
,也就是说本例中的f(x) != f(f(x))
。
有趣的是PySlice_AdjustIndices中有如下评论:
/* this is harder to get right than you might think */
最后,请注意,python docs中没有描述所讨论情况的处理。
我正在尝试理解以下行为,欢迎任何参考(尤其是官方文档)或评论。
让我们考虑一个列表:
>>> x = [1,2,3,4,5,6]
这按预期工作
>>> x[-1:-4:-1]
[6, 5, 4]
但我很惊讶下面是空的:
>>> x[0:-4:-1]
[]
因此,我很惊讶下面不是空的
>>> x[0:-len(x)-1:-1]
> [1]
特别是考虑到
>>> x[0:-len(x):-1]
[]
还有那个
>>> x[0:-len(x)-1]
[]
为空。
事实
> x[-1:-4:-1]
[6, 5, 4]
> x[0:-4:-1]
[]
应该不会让你吃惊!很明显,您可以在向后的步骤中将列表从最后一个元素切片到 fourth-last 元素,但不能从第一个元素切片。
在
x[0:i:-1]
i
必须是 < -len(x)
才能解析为索引 < 0
,以便结果包含元素。
slice 的语法很简单:
x[start:end:step]
意味着,切片开始于 start
(此处:0
)并结束于 before end
(或任何引用的索引)否定 end
)。 -len(x)
解析为 0
,因此从 0
开始到 0
结束的切片长度为 0
,不包含任何元素。然而,-len(x)-1
将解析为实际的 -1
,导致长度为 1
的切片从 0
.
让end
在后向切片中留空更直观地理解:
> l[2::-1]
[3, 2, 1]
> l[0::-1]
[1]
我被指向了参考实现(hattip to the Anonymous Benefactor),发现从那里理解行为是相当简单的。完整地说,恕我直言,这种行为不直观,但它定义明确并且与参考实现相匹配。
有两个 CPython 文件相关,即描述 list_subscript and PySlice_AdjustIndices 的文件。在这种情况下从列表中检索切片时,将调用 list_subscript。它调用 PySlice_GetIndicesEx,后者又调用 PySlice_AdjustIndices。 现在 PySlice_AdjustIndices 包含简单的 if/then 语句,用于调整索引。最后它 returns 切片的长度。对于我们的例子,行
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]
传给adjust时,就变成了长度为0的x[0:len(x)-1:-1]
,也就是说本例中的f(x) != f(f(x))
。
有趣的是PySlice_AdjustIndices中有如下评论:
/* this is harder to get right than you might think */
最后,请注意,python docs中没有描述所讨论情况的处理。