Python的切片表示法是如何工作的?也就是说:当我编写[x:y:z]、a[:]、a]::2]等代码时,我如何理解哪些元素最终会出现在切片中?请在适当的地方附上参考资料。


另请参见:为什么切片和范围上限是互斥的?


当前回答

关于序列的索引,需要记住的重要思想是

非负指数从序列中的第一项开始;负索引从序列的最后一项开始(因此仅适用于有限序列)。

换言之,负索引右移序列长度:

              0   1   2   3   4   5   6   7   ...
            -------------------------
            | a | b | c | d | e | f |
            -------------------------
...  -8  -7  -6  -5  -4  -3  -2  -1

考虑到这一点,订阅和切片很简单。

订阅

订阅使用以下语法:*

sequence[index]

订阅在索引处选择序列中的单个项目:

>>> 'abcdef'[0]
'a'
>>> 'abcdef'[-6]
'a'

订阅引发超出范围的索引的IndexError:

>>> 'abcdef'[100]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range

切片

切片使用以下语法:**

sequence[start:stop:step]

切片选择序列中的一系列项目,从包含开始到不包含结束:

>>> 'abcdef'[0:2:1]
'ab'
>>> 'abcdef'[0:-4:1]
'ab'
>>> 'abcdef'[-6:-4:1]
'ab'
>>> 'abcdef'[-6:2:1]
'ab'
>>> 'abcdef'[1:-7:-1]
'ba'
>>> 'abcdef'[-5:-7:-1]
'ba'

切片默认为序列中最完整的项目范围,因此它对省略或等于“无”的任何开始、停止或步骤使用以下默认值:***

步骤默认为1;如果步骤为正start默认为0(第一项索引),stop默认为start+len(序列)(最后一项索引加一);如果步骤为负start默认为-1(最后一项索引),stop默认为start-len(序列)(第一项索引减一)。

>>> 'abcdef'[0:6:1]
'abcdef'
>>> 'abcdef'[::]
'abcdef'
>>> 'abcdef'[-1:-7:-1]
'fedcba'
>>> 'abcdef'[::-1]
'fedcba'

切片为等于零的步骤引发ValueError:

>>> 'abcdef'[::0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: slice step cannot be zero

切片不会为超出范围的开始或停止引发IndexError(与订阅相反):

>>> 'abcdef'[-100:100]
'abcdef'

*表达式sequence[index]和sequence__getitem_(索引)是等效的。

**表达式sequence[start:stop:step]、sequence[Sslice(start,stop,step)]和sequence__getitem_(slice(start,stop,step))是等效的,其中内置类slice实例包start,stop和step。

***表达式sequence[:]、sequence[::]和sequence[None:None:None]使用start、stop和step的默认值。

其他回答

Python教程对此进行了讨论(向下滚动一点,直到您了解到关于切片的部分)。

ASCII艺术图也有助于记住切片的工作方式:

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

记住切片工作方式的一种方法是将索引视为字符之间的指针,第一个字符的左边缘编号为0。然后,n个字符串的最后一个字符的右边缘具有索引n。

以下是字符串索引的示例:

 +---+---+---+---+---+
 | H | e | l | p | A |
 +---+---+---+---+---+
 0   1   2   3   4   5
-5  -4  -3  -2  -1

str="Name string"

切片示例:[开始:结束:步骤]

str[start:end] # Items start through end-1
str[start:]    # Items start through the rest of the array
str[:end]      # Items from the beginning through end-1
str[:]         # A copy of the whole array

以下是示例用法:

print str[0] = N
print str[0:2] = Na
print str[0:7] = Name st
print str[0:7:2] = Nm t
print str[0:-1:2] = Nm ti

关于序列的索引,需要记住的重要思想是

非负指数从序列中的第一项开始;负索引从序列的最后一项开始(因此仅适用于有限序列)。

换言之,负索引右移序列长度:

              0   1   2   3   4   5   6   7   ...
            -------------------------
            | a | b | c | d | e | f |
            -------------------------
...  -8  -7  -6  -5  -4  -3  -2  -1

考虑到这一点,订阅和切片很简单。

订阅

订阅使用以下语法:*

sequence[index]

订阅在索引处选择序列中的单个项目:

>>> 'abcdef'[0]
'a'
>>> 'abcdef'[-6]
'a'

订阅引发超出范围的索引的IndexError:

>>> 'abcdef'[100]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range

切片

切片使用以下语法:**

sequence[start:stop:step]

切片选择序列中的一系列项目,从包含开始到不包含结束:

>>> 'abcdef'[0:2:1]
'ab'
>>> 'abcdef'[0:-4:1]
'ab'
>>> 'abcdef'[-6:-4:1]
'ab'
>>> 'abcdef'[-6:2:1]
'ab'
>>> 'abcdef'[1:-7:-1]
'ba'
>>> 'abcdef'[-5:-7:-1]
'ba'

切片默认为序列中最完整的项目范围,因此它对省略或等于“无”的任何开始、停止或步骤使用以下默认值:***

步骤默认为1;如果步骤为正start默认为0(第一项索引),stop默认为start+len(序列)(最后一项索引加一);如果步骤为负start默认为-1(最后一项索引),stop默认为start-len(序列)(第一项索引减一)。

>>> 'abcdef'[0:6:1]
'abcdef'
>>> 'abcdef'[::]
'abcdef'
>>> 'abcdef'[-1:-7:-1]
'fedcba'
>>> 'abcdef'[::-1]
'fedcba'

切片为等于零的步骤引发ValueError:

>>> 'abcdef'[::0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: slice step cannot be zero

切片不会为超出范围的开始或停止引发IndexError(与订阅相反):

>>> 'abcdef'[-100:100]
'abcdef'

*表达式sequence[index]和sequence__getitem_(索引)是等效的。

**表达式sequence[start:stop:step]、sequence[Sslice(start,stop,step)]和sequence__getitem_(slice(start,stop,step))是等效的,其中内置类slice实例包start,stop和step。

***表达式sequence[:]、sequence[::]和sequence[None:None:None]使用start、stop和step的默认值。

语法为:

a[start:stop]  # items start through stop-1
a[start:]      # items start through the rest of the array
a[:stop]       # items from the beginning through stop-1
a[:]           # a copy of the whole array

还有一个步长值,可用于上述任何一项:

a[start:stop:step] # start through not past stop, by step

要记住的关键点是:stop值表示不在所选切片中的第一个值。因此,停止和开始之间的区别是所选元素的数量(如果步骤为1,则为默认值)。

另一个特点是start或stop可以是负数,这意味着它从数组的末尾开始计数,而不是从开始计数。因此:

a[-1]    # last item in the array
a[-2:]   # last two items in the array
a[:-2]   # everything except the last two items

类似地,步骤可以是负数:

a[::-1]    # all items in the array, reversed
a[1::-1]   # the first two items, reversed
a[:-3:-1]  # the last two items, reversed
a[-3::-1]  # everything except the last two items, reversed

如果项目比你要求的少,Python对程序员很友好。例如,如果您请求一个[:-2],而一个只包含一个元素,则会得到一个空列表而不是一个错误。有时你会更喜欢错误,所以你必须意识到这可能会发生。

与切片对象的关系

切片对象可以表示切片操作,即:

a[start:stop:step]

相当于:

a[slice(start, stop, step)]

根据参数的数量,切片对象的行为也略有不同,类似于range(),即切片(stop)和切片(start,stop[,step])都受支持。要跳过指定给定参数,可以使用None,例如[start:]等同于[sslice(start,None)]或[::-1]等同于[Sslice(None,None,-1)]。

虽然基于:的表示法对简单切片非常有用,但slice()对象的显式使用简化了切片的编程生成。

我的大脑似乎很乐意接受lst[开始:结束]包含开始项。我甚至可以说这是一个“自然的假设”。

但偶尔会有一种怀疑悄悄出现,我的大脑会要求我保证它不包含结尾元素。

在这些时刻,我依靠这个简单的定理:

for any n,    lst = lst[:n] + lst[n:]

这个漂亮的属性告诉我,lst[start:end]不包含end-th项,因为它位于lst[end:]中。

注意,这个定理对任何n都是正确的。例如,您可以检查

lst = range(10)
lst[:-42] + lst[-42:] == lst

返回True。