如何用切片符号a [:: - 1]来解释序列的反转

时间:2017-06-06 09:16:56

标签: python string slice

来自python.org tutorial

  

切片索引具有有用的默认值;省略的第一个索引默认为零,省略的第二个索引默认为要切片的字符串的大小。

>>> a = "hello"
>>> print(a[::-1])
olleh

正如教程所说,a[::-1]应该等于a[0:5:-1]

a[0:5:-1]为空,如下所示:

>>> print(len(a[0:5:-1]))
0

问题不是explain-slice-notation的重复。那个问题是关于python中切片的一般用法。

7 个答案:

答案 0 :(得分:21)

我认为文档可能对此有点误导,但如果省略则切片的可选参数与使用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

对于否定的stepNone的替换值为len(a) - 1的{​​{1}}和start的{​​{1}}:

-len(a) - 1

这可以帮助您想象它:

end

答案 1 :(得分:3)

所有这一切都是slice。你选。开始停止和步骤所以基本上你说它应该从头开始直到开始但向后(-1)。

如果你用-2做它会跳过字母:

>>> a[::-2]
'olh'

当你从第一个字母开始[0:5:-1]时,直接回到5,因此它会停止。只有当您尝试[-1::-1]时才会通过执行否定步骤1来正确地开始。

修改以回复评论

正如documentation所说的那样

  

省略的第二个索引默认为字符串的大小   切片。

假设我们strlen(str) = 5。当你对字符串进行切片并省略时,请忽略,第二个数字默认为被切片的字符串的长度,在本例中为5。 即str[1:] == str[1:5]str[2:] == str[2:5]。句子指的是原始对象的长度,而不是新切片的对象。

此外,this answer很棒

答案 2 :(得分:3)

你对踩踏的行为感到困惑。要获得相同的结果,您可以做的是:

a[0:5][::-1]
'olleh'

事实上,步进想要“绕圈”。在你的情况下倒退,但是你通过拨打a[0:5:-1]来限制它的移动。

答案 3 :(得分:2)

a[0:5:-1]没有多大意义,因为当您使用此表示法时,索引意味着:a[start:end:step]。当您使用负步时,您的结束值需要处于比起始值更“早”的位置。

答案 4 :(得分:1)

您会注意到第三个切片参数step未在您引用的教程部分中显示。该特定片段采取积极步骤。

当您添加消极步骤的可能性时,行为实际上非常直观。空start参数指的是序列中的任何一端,以step值指示的方向逐步遍历整个序列。换句话说,如果你有一个正步骤,它指的是最低指数(计数),如果你有一个负步骤,它指的是最高指数(倒计时)。同样地,一个空的end参数指的是在以适当的方向踩到之后最终会出现的序列中的任何一端。

答案 5 :(得分:0)

您所指出的文档对默认值完全不正确。但是,除了那个小错误外,它们是一致的。您可以在这里查看我所指的文档:https://docs.python.org/3/library/stdtypes.html#common-sequence-operations

请注意,根据文档,该行为在定义上是正确的:

  

从第i步到第j步的s切片被定义为   索引为x = i + n * k的项,使得0 <= n <(j-i)/ k。其他   换句话说,索引是i,i + k,i + 2 * k,i + 3 * k等,在j时停止   已达到(但不包括j)。

当您这样做:

>>> a = "hello"
>>> y = a[0:5:-1]

我们有i == 0j == 5k == -1。因此,我们从x = i + n*kn的{​​{1}}的索引0处抓取项目。但是,请注意(j-i)/k。没有(j-i)/k == (5-0)/-1 == -5这样的n,因此您得到了空字符串:

0 <= n < -5

如有疑问,请>>> y '' (这几乎总是我们想要的)

几乎总是这样,当您对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切片之后始终执行step子句 只是更安全。因此,我几乎总是start:stop开始,至少在进行原型设计或创建新模块时,首先要考虑正确性/可读性。这比执行单个切片的性能要差,但是如果性能是一个问题,那么您可以做的可读性较低:

y = x[start:stop][::step]

HTH。

答案 6 :(得分:0)

对于Python切片序列[start:stop:step] ,已得出以下规则:

  1. start:stop = start:stop:1
  2. start:stop:(+或-)步骤-表示遍历序列中的N个项目。但是,(-)表示向后遍历
  3. 请记住,序列中最后一项的位置是-1,而比它更早的位置是-2,依此类推。

#开始:停止:+步骤规则

  1. 总是向前移动
  2. 始终从序列开始作为积极的一步(向前)
  3. 从请求位置开始,在请求位置停止,但不包括项目停止位置
  4. 默认开始:如果未提供开始,请从0开始
  5. 默认停止::如果未提供停止,则表示直到序列的结束包括最后一个值
  6. 如果停靠位置的项目无法到达(项目超出序列遍历的末尾),则slice不返回任何内容

#开始:停止:分步规则

  1. 总是反向遍历
  2. 如果提供了起始位置,请从此处开始,但要反向移动(向后退)
  3. 如果提供了停靠点,则在该处停止走动,但不包括此
  4. 默认开始:如果未提供开始位置,则开始位置是序列的最后一个位置(因为遍历为负)
  5. 默认停止位置::如果未提供停止位置,则它是列表的开头(位置0)
  6. 如果停靠位置的项目无法到达(项目超出序列遍历的末尾),则slice不返回任何内容