python双冒号,-1为第三个参数

时间:2016-03-13 20:42:16

标签: python python-2.7

a = [1,2,3,4,5]为例。从我的直觉来看,我认为a[::-1]a[0:len(a):-1]相同。但结果变成了错误:

>>> a = [1,2,3,4,5]
>>> print a[::-1]
[5, 4, 3, 2, 1]
>>> print a[0:len(a):-1]
[]
>>> print a[0:3:-1]
[]
>>> print a[0:2:-1]
[]
>>> print a[:2:-1]
[5, 4]
>>> print a[:0:-1]
[5, 4, 3, 2]
>>> print a[0:-1]
[1, 2, 3, 4]

我实际上无法理解最后6次尝试的输出。谁能给我一些想法?谢谢你。

3 个答案:

答案 0 :(得分:10)

要使用的语法是[start:end:step],其中end不包括在内。

Python遵循一些基于可能含义的规则(可能它们不是你的意思,但语言设计者在这种情况下获得最终投票)。我们将进一步研究确切的规则。

a[::-1]是撤消列表的快捷方式。如果我们说要向后工作而没有任何界限,我们可能意味着从结尾移动到开始。

a[0:len(a):-1]表示从0开始,而-1表示从len(a)开始。请注意,这是不可能的(我们最终会得到无数个负数),因此结果为空。 a[0:3:-1]a[0:2:-1]有同样的问题。

在最后一个示例a[0:-1]中,负一个索引表示最后一个元素。您可能意味着从开始到结束。请注意,终点不包括在内。这给出了除最后一个元素之外的所有元素(也可以指定为a[:-1])。

使用a[:2:-1],您可以向后指定一个动作,因此可能意味着从最后一个元素向后移动到2个索引。这会在您的示例中显示[5,4]a[:0:-1]情况类似,但移动发生在开头,给出[5,4,3,2]

参考cpython source code,我们可以看到实际规则。

  1. 如果未给出步骤,则等于1
  2. 如果未给出起始值,如果step不是负数,则选择默认start为0;如果是
  3. ,则选择length -1
  4. 如果没有给出结束值,如果step不是负数,则选择默认结束为长度;如果是,则选择-1(这些值允许保留最后一个元素,知道终点是非包容性的)
  5. 如果给出了

    ,则对开始值和结束值进行一些调整
    1. 如果该值小于0,则为其添加长度
    2. 如果仍然小于0,如果步骤为非负,则将其设置为0,否则将其设置为-1
    3. 如果大于或等于长度,如果步长为负,则将其设置为小于长度,否则等于长度
    4. 请注意,在大多数情况下,规则会确定可以准确指定的值以获取等效表单。例外情况是默认规则确定-1的起点或终点。如果我们给出该值,修改值的规则将改变它。

      应用这些规则我们得到

      • a[::-1]使用start of length-1(默认值),结束时为-1(默认值),步长为-1
      • a[0:len(a):-1]a[0:3:-1]a[0:2:-1]使用给定的值
      • a[:0:-1]使用长度为1的开头(默认值),结束为0,步长为-1
      • a[:2:-1]使用长度为1的开头(默认值),结束时为2,步长为-1
      • a[0:-1]使用0开头,长度为1(已修改),步长为1(默认值)

      此时,我们可以确定是否可以进行选择。在空的情况下,由于步骤为负并且开始<结束,我们现在看到这是不可能的。

答案 1 :(得分:1)

当有三个参数时,表示步骤。即-1表示步骤1向后。这就是为什么当你的第一个参数小于第二个参数时,你得到一个空列表。

如果有两个参数,则表示从结束开始计算的最后一个元素。

如果将第一个参数留空,Python再次将第二个参数作为范围结束索引并从结束开始计数,因为该步骤为负。

答案 2 :(得分:1)

有关如何解释各种尝试的结果,请参阅Matthew's anser

在你的问题的各行之间,我读到你想要复制a[::-1]的行为,但明确地传递了切片的startstop

Python tutorial's first closer look at strings提到了这个有用的助记符:

  

记住切片如何工作的一种方法是将索引视为   将指向字符,使用第一个字符的左边缘   字符编号为0.然后是a的最后一个字符的右边缘    n 字符的字符串具有索引 n ,例如:

     
 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1
     

第一行数字给出了索引0 ... 6的位置   字符串;第二行给出相应的负指数。   从 i j 的切片由边之间的所有字符组成   分别标记为 i j

当然,相同的切片规则适用于其他序列,例如列表和元组。本教程提及 [1] 的内容是否定步骤,你必须使用移位索引 - 指向 - 之间-items,像这样:

 ┎───┰───┰───┰───┰───┰───┒
 ┃ P ┃ y ┃ t ┃ h ┃ o ┃ n ┃ <== For backwards slicing (i.e. negative step)
 ┞───╀───╀───╀───╀───╀───┦
     0   1   2   3   4   5
-7  -6  -5  -4  -3  -2  -1

这是因为索引 序列项之间 相反,切片的stop参数是一个排他限制,即结果序列将以step 覆盖的最后一项结束索引为{{1}的那一项}。

从这个移位的伪索引表我们可以看到,要通过使用显式边界切片来反转整个序列,我们必须从stop(或更高)开始。我们进一步看到,我们可以使用非负索引作为len(a) - 1,并且仍然将原始序列的第一项作为结果序列的最后一项。 stop已经在第二个原始项目结束。我们无法将[len(a)-1:0:-1]用作-1,因为这是在stop独立的最后一项之后引用位置的简写。我们必须使用len(a)作为-len(a) - 1(或更低)代替:

stop

如果一个人明确指定了边界,那么可能是因为在更高版本的代码中只能使用序列的一部分时它们可以被调整。对于需要调整的代码,需要了解当前的修订版本,以便能够对要改变的内容做出明智的决定。不用说,>>> a[len(a)-1:-len(a)-1:-1] [5, 4, 3, 2, 1] a[len(a)-1:-len(a)-1:-1]更难以理解,list(reversed(a))可以很容易地用边界扩充:

>>> list(reversed(a[2:4]))  # referring to indices of original sequence
[4, 3]
>>> list(reversed(a))[1:3]  # referring to indices of reversed sequence
[4, 3]

[1] 教程没有提到的原因可能是在Python 2.2之前,切片时使用步骤的可能性只能用于NumPy序列(和也许是其他第三方序列),但Python的内置序列列表,元组和字符串并不支持。 Python 2.3 added the implementation for this 'extended slicing' semantics用于内置序列类型。