我认为我理解了python中列表切片的基础知识,但是在切片上使用负步骤时收到了意外错误,如下所示:
>>> a = list(range(10))
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[:-1]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> a[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[:-1:-1]
[]
(请注意,这是在Python 3.5中运行)
为什么没有[: - 1:-1]反向跳过a [: - 1]切片的方式与通过[:: - 1]整个列表的方式相同?
我意识到你也可以使用list.reverse(),但试图更好地理解底层的python切片功能。
答案 0 :(得分:22)
-1
中的第一个a[:-1:-1]
并不代表您的想法。
在切片中,负起始/结束索引不按字面解释。相反,它们用于方便地引用列表的末尾(即它们相对于len(a)
)。无论切片的方向如何,都会发生这种情况。
这意味着
a[:-1:-1]
相当于
a[:len(a)-1:-1]
在反向切片期间省略时,起始索引默认为len(a)-1
,使上述内容等同于
a[len(a)-1:len(a)-1:-1]
这总是给出一个空列表,因为开始和结束索引是相同的,而结束索引是独占的。
要反向切换到第0个元素并包含第0个元素,您可以使用以下任何符号:
>>> a[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[:None:-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[:-len(a)-1:-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
答案 1 :(得分:8)
当您输入[1, 2, 3, ...][1:4:1]
时,它与[1, 2, 3, ...][slice(1, 4, 1)]
相同。所以1:4:1
是slice
对象的简写。 slice
签名为slice(stop)
或slice(start, stop[, step])
,您也可以使用None
作为参数。
:: -> slice(None, None, None)
:4 -> slice(4)
# and so on
假设我们有[a: b: c]
。索引的规则如下:
c
。默认值为+1
,c
的符号表示步骤的前进或后退方向。 c
的绝对值表示步长。 a
。当c
为正数或None
时,a
的默认值为0
。当c
为否定时,a
的默认值为-1
。b
。当c
为正数或None
时,b
的默认值为len
。当c
为b
的否定默认值为-(len+1)
时。注1 :优雅地处理Python中的退化切片:
len
或0
替换。 c
)。 注意2 :粗略地说,当条件(a < b) if (c > 0) else (a > b)
为True
时,Python会选择元素(每一步都更新a += c
)。此外,所有负面指数都替换为len - index
。
如果你结合这个规则和注释,你有一个空列表是有道理的。在你的情况下:
In[1]: [1, 2, 3, 4, 5, 6][:-1:-1] # `c` is negative so `a` is -1 and `b` is -1
Out[1]: []
# it is the same as:
In[2]: [1, 2, 3, 4, 5, 6][-1: -1: -1] # which will produce you an empty list
Out[2]: []
关于切片表示法的讨论非常好:Explain Python's slice notation!
答案 2 :(得分:4)
我通常发现切片range
- 对象很有用(这只能在python3中使用 - 在python2 range
中产生list
并且xrange
不能如果我需要查看哪些索引用于给定长度的列表:
>>> range(10)[::-1]
range(9, -1, -1)
>>> range(10)[:-1]
range(0, 9)
在你的最后一个案例中:
>>> range(10)[:-1:-1]
range(9, 9, -1)
这也解释了发生了什么。第一个索引是9,但是9不低于停止索引9(请注意,在python中,停止索引是排除)所以它在没有给出任何元素的情况下停止。
请注意,索引也可以按顺序应用:
>>> list(range(10))[::-1][:-1] # first reverse then exclude last item.
[9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> list(range(10))[:-1][::-1] # other way around
[8, 7, 6, 5, 4, 3, 2, 1, 0]
答案 3 :(得分:1)
Python的切片起初看起来相当简单,但它们的行为实际上是quite complex(注释3和5在这里是相关的)。如果您有切片a[i:j:k]
:
i
或j
为否定,则会引用a
末尾的索引(因此a[-1]
指的是a
的最后一个元素)如果未指定i
或j
,或None
,则默认为a
的结尾,但 >结尾取决于k
:
k
为肯定,则您向前切片,因此i
变为0而j
变为len(a)
如果k
为否定,则会向后切片,因此i
变为len(a)
而j
成为{{{}之前的元素1}}。
注意: a
无法替换为-1,因为这样做会导致Python将j
视为最后的 <{1}}的元素,而不是j
之前的(不存在)元素。要获得所需的行为,您必须使用a
(或a[0]
)代替-len(a)-1
,这意味着要转到-(len(a)+1)
,切片将从最后一个元素开始j
向左移动a[j]
个元素,然后再添加一个元素,在a
开始之前结束,因此在切片中包含len(a)
。
因此,a
表示&#34;从a[0]
结束,a[:-1:-1]
(因为a
未指定且a[-1]
为否定),到i
的最后一个元素(从k
开始),步长为-1和#34;。 a
和j == -1
相等 - 您在同一个地方开始和停止切片 - 因此表达式的计算结果为空列表。
要反转i
,您可以使用j
。这样,切片从倒数第二个元素a[:-1]
开始(因为a[-2::-1]
不包括a[-2]
)并且向后移动直到元素&#34;之前&#34; a[:-1]
,表示切片中包含a[-1]
。
a[0]
答案 4 :(得分:1)
slice
的工作方式类似于range
,因为当您将step
参数设为负数时,start
和stop
参数的工作方向相反
>>> list(range(9, -1, -1)) == a[::-1]
True
一些可能有助于使其更清晰的例子:
>>> a[6:2:-2]
[6, 4]
>>> a[0:None:1] == a[::]
True
>>> a[-1:None:-1] == a[::-1]
True
>>> a[-2:None:-1] == a[:-1][::-1]
True
答案 5 :(得分:0)
以一种简单的方式可以理解,如果最后的a[::-1]
-1反转了字符串。
现在
a=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
a[::-1]=[9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
现在a[:-1:-1]
-1中间没有任何意义,因为现在它是第一个元素,这将提供一个空列表。
而a[-1::-1]
为您提供了完整的清单,很有意义。