[英]How to explain the reverse of a sequence by slice notation a[::-1]
切片索引具有有用的默认值; 省略的第一个索引默认为零,省略的第二个索引默认为要切片的字符串的大小。
>>> a = "hello"
>>> print(a[::-1])
olleh
正如教程所说a[::-1]
应该等于a[0:5:-1]
但是a[0:5:-1]
是空的,如下所示:
>>> print(len(a[0:5:-1]))
0
问题不是解释切片符号的重复。 那个问题是关于python中切片的一般用法。
我认为文档可能对此有点误导,但是如果省略切片的可选参数与使用None
相同:
>>> a = "hello"
>>> a[::-1]
'olleh'
>>> a[None:None:-1]
'olleh'
您可以看到这两个上面的切片与CPython字节码完全相同:
>>> import dis
>>> dis.dis('a[::-1]') # or dis.dis('a[None:None:-1]')
1 0 LOAD_NAME 0 (a)
3 LOAD_CONST 0 (None)
6 LOAD_CONST 0 (None)
9 LOAD_CONST 2 (-1)
12 BUILD_SLICE 3
15 BINARY_SUBSCR
16 RETURN_VALUE
对于否定step
, None
的替换值为len(a) - 1
表示start
而-len(a) - 1
表示end
:
>>> a[len(a)-1:-len(a)-1:-1]
'olleh'
>>> a[4:-6:-1]
'olleh'
>>> a[-1:-6:-1]
'olleh'
这可以帮助您将其可视化:
h e l l o
0 1 2 3 4 5
-6 -5 -4 -3 -2 -1
它只是切片 。 你选。 开始停止和步骤所以基本上你说它应该从头开始直到开始但向后(-1)。
如果你用-2做它会跳过字母:
>>> a[::-2]
'olh'
在做[0:5:-1]
你从第一个字母开始直接回到5,因此它会停止。 只有当你尝试[-1::-1]
它才能正确地通过做负1的步骤到达开头。
编辑以回答评论
正如文件所指出的那样
省略的第二个索引默认为要切片的字符串的大小。
让我们假设我们有str
( len(str) = 5
。 当你对字符串进行切片并省略时,请忽略,第二个数字默认为被切片的字符串的长度,在这种情况下 - 5.即str[1:] == str[1:5]
, str[2:] == str[2:5]
。 句子指的是原始对象的长度而不是新切片的对象。
此外, 这个答案很棒
你对步进的行为感到困惑。 要获得相同的结果,您可以做的是:
a[0:5][::-1]
'olleh'
事实上,步进想要在你的情况下向后“绕圈”,但是你通过调用a[0:5:-1]
来限制它的运动。
a[0:5:-1]
没有多大意义,因为当你使用这种表示法时,索引意味着: a[start:end:step]
。 当您使用负步时,您的结束值需要处于比起始值更“早”的位置。
您会注意到第三个切片参数,即step
,未在您引用的教程部分中显示。 该特定片段采取积极步骤。
当你添加消极步骤的可能性时,行为实际上非常直观。 空start
参数指的是序列中的任何一端开始以step
值指示的方向逐步通过整个序列。 换句话说,如果你有一个正步骤,它指的是最低指数(计数),如果你有一个负步骤,它指的是最高指数(倒计时)。 同样,空end
参数指的是在步进通过适当方向后最终结束的序列中的任何一端。
正如您所指出的,文档对于默认值是不正确的。 但是,除了那个小错误之外,它们是一致的。 您可以在此处查看我所指的文档: https : //docs.python.org/3/library/stdtypes.html#common-sequence-operations
具有步骤k的从i到j的s的片被定义为具有索引x = i + n * k的项的序列,使得0 <= n <(ji)/ k。 换句话说,索引是i,i + k,i + 2 * k,i + 3 * k等等,当到达j时停止(但是从不包括j)。
当你这样做时:
>>> a = "hello"
>>> y = a[0:5:-1]
我们有i == 0
, j == 5
, k == -1
。 所以我们抓住索引x = i + n*k
,从0
开始到n
,然后上升到(ji)/k
。 但是,请注意(ji)/k == (5-0)/-1 == -5
。 没有n
这样0 <= n < -5
,所以你得到空字符串:
>>> y
''
a[start:stop][::step]
疑问的时候做a[start:stop][::step]
(这几乎总是我们想要的) 几乎总是这样的情况,当你将一个消极的步骤传递给x[start:stop:step]
东西时,你想要发生的是先选择子选择,然后step
倒退(即我们通常想要的) x[start:stop][::step]
。
此外,为了增加混乱,恰好是这种情况
x[start:stop:step] == x[start:stop][::step]
如果step > 0
。 例如:
>>> x = list(range(10))
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x[2:6:2]
[2, 4]
>>> x[2:6][::2]
[2, 4]
>>> x[1:10][::3]
[1, 4, 7]
>>> x[1:10:3]
[1, 4, 7]
不幸的是,当step < 0
时,这不成立,即使它认为它应该是诱人的。
在被这几次烧毁之后,我意识到在执行start:stop
slice 之后总是执行step子句会更安全。 所以我几乎总是从y = x[start:stop][::step]
,至少在原型设计或创建一个正确性/可读性是原始问题的新模块时。 这比执行单个切片的性能要差,但如果性能是一个问题,那么您可以做的可读性较低:
y = x[start:stop:step] if step > 0 else x[stop:start:step]
HTH。
对于序列[start:stop:step]的 Python切片,已经导出了以下规则:
#start:stop:+ step规则
#start:stop:-step规则
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.