>>>"helloworld"[::1]
'helloworld'
>>>"helloworld"[::-1]
'dlrowolleh'
根据语法str[start:end:step]
。在这两种情况下,开始默认为 0。在第一种情况下,字符串从索引值 0 开始打印。但在第二种情况下,字符串从索引值 -1 开始打印。
我的问题是为什么在后一种情况下从 -1 打印字符串,为什么会这样?
根据文档(强调添加):
步骤 k 从 i 到 j 的 s 切片定义为具有索引 x = i + n*k 的项目序列,使得 0 <= n < (ji)/k。换句话说,索引是 i、i+k、i+2*k、i+3*k 等等,当达到 j 时停止(但从不包括 j)。如果 i 或 j 大于 len(s),则使用 len(s)。如果 i 或 j 被省略或没有,它们将成为“结束”值(结束取决于 k 的符号)。注意,k 不能为零。如果 k 为无,则将其视为 1。
这意味着如果切片步幅为正,则省略的切片开始是序列的开始,而省略的切片结束是序列的结尾。如果切片步幅为负,则相反。如果您填写以下两个值之一,您可以看到这一点:
>>> '0123456'[:3]
'012'
>>> '0123456'[:3:-1]
'654'
>>> '0123456'[3:]
'3456'
>>> '0123456'[3::-1]
'3210'
考虑这一点的一种方法是将序列可视化为一个循环,其中起点和终点是同一点。当您省略切片的一端时,您只是指定使用这个“两端点”作为端点,而不是从那里往哪个方向走。步幅标志告诉您要走哪条路,这决定了您是将“两端点”视为序列的开始还是结束。
扩展切片组件都默认为 None (相对于 0 和sys.maxint
简单切片):
>>> class A:
... def __getitem__(self, s):
... return s
...
>>> A()[::-1]
slice(None, None, -1)
>>> A()[:]
slice(0, 9223372036854775807, None)
因此,没有自动假定切片应该默认从零开始。
可视化这个
记住切片如何工作的最佳方法是将索引视为字符之间的指向,第一个字符的左边缘编号为 0。然后,n 个字符的字符串的最后一个字符的右边缘具有索引 n,例如:
+---+---+---+---+---+
| H | e | l | l | o |
+---+---+---+---+---+
0 1 2 3 4 5
-5 -4 -3 -2 -1
索引可以是负数,从右开始计数。 但是注意-0其实和0是一样的,所以从右数不算!
In [105]: "helloworld"[-0]
Out[105]: 'h'
In [106]: "helloworld"[0]
Out[106]: 'h'
即为什么反向索引从-1开始
In [107]: "helloworld"[-1]
Out[107]: 'd'
用于获取字符串的倒数第二个索引,[-2]
即,需要最后一个字符的负步进,添加该步进以获取下一个索引
In [108]: "helloworld"[-1 + -1]
Out[108]: 'l'
在 python 中,字符串索引如下所示。
"H e l l o"
0 1 2 3 4
-4 -3 -2 -1 0
将使用的索引取决于您所取切片的方向。因为您给出的步骤是相反的方向,所以它使用下面的索引。但是,这在文档中没有明确说明。
编辑:
我实际上重新检查并有趣
str[::-1]
str[0::-1]
str[-1::-1]
所有返回相同的值。所以我在原始帖子中所说的似乎是错误的。它看起来更像是语言中的错误或特殊情况处理。
使用 step = 1,不出所料,您将获得原始字符串。
在 step = -1 的情况下,python 可能实现了一种特殊情况:颠倒顺序。
毕竟, slice [start:end]
, as[:]
返回完整的 slice,这是预期的行为。所以将其视为两阶段操作:获取切片(在您的情况下为完整副本),应用步进(在您的情况下反向)。
您所看到的称为striding
:
>>> 'helloworld'[::1]
返回所有元素同时
>>> 'helloworld'[::2]
'hlool'
返回每个第二个元素。所以,现在试试:
>>> 'helloworld'[::-2]
'drwle'
这从最后返回每 2 个元素。因此,自然地,从末尾开始的所有元素都是反转的字符串:
>>> 'helloworld'[::-1]
'dlrowolleh'
-1
如果在字符串反转时start 不是隐式的,那将毫无意义。-1
如果您尝试使用显式索引,您将看到在用作步骤时起始索引必须位于结束索引的右侧:
>>> "helloworld"[0:-1:-1]
''
>>> "helloworld"[-1:0:-1]
'dlrowolle'
就像在正常方式切片时,范围包括起点而不包括终点,所以h
at index0
不是范围的一部分。这是(AFAIK)切片符号的限制,它不可能对整个字符串进行显式反转,因为这不起作用:
>>> "helloworld"[-1:-1:-1]
''
所以切片和反转函数必须有一个特殊情况:
def slice_and_reverse(s, a, b):
"Return a slice of s from a to but not including b, reversed."
if a == 0:
return s[b - 1::-1]
else:
return s[b - 1:a - 1:-1]