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


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


当前回答

基本的切片技术是定义起点、终点和步长(也称为步幅)。

首先,我们将创建一个用于切片的值列表。

创建两个要切片的列表。第一个是从1到9的数字列表(列表a)。第二个也是数字列表,从0到9(列表B):

A = list(range(1, 10, 1)) # Start, stop, and step
B = list(range(9))

print("This is List A:", A)
print("This is List B:", B)

索引A中的数字3和B中的数字6。

print(A[2])
print(B[6])

基本切片

用于切片的扩展索引语法是aList[start:stop:step]。start参数和step参数都默认为None,唯一需要的参数是stop。您是否注意到这与使用范围定义列表A和B的方式类似?这是因为切片对象表示由范围(开始、停止、步骤)指定的索引集。

如您所见,仅定义stop返回一个元素。由于start默认为none,这意味着只检索一个元素。

需要注意的是,第一个元素是索引0,而不是索引1。这就是为什么我们在本练习中使用两个列表。列表A的元素根据序号位置进行编号(第一个元素是1,第二个元素是2,等等),而列表B的元素是用于对其进行索引的数字(对于第一个元素,[0],等等)。

通过扩展索引语法,我们可以检索一系列值。例如,使用冒号检索所有值。

A[:]

要检索元素的子集,需要定义开始和停止位置。

给定模式aList[start:stop],从列表A中检索前两个元素。

其他回答

如果我们可以将切片与范围联系起来,这很容易理解,因为范围给出了索引。我们可以将切片分为以下两类:


1.无台阶或台阶>0。例如,[i:j]或[i:j:k](k>0)

假设序列为s=[1,2,3,4,5]。

如果0<i<len(s)和0<j<len,则[i:j:k]->范围(i,j,k)

例如,[0:3:2]->范围(0,3,2)->0,2

如果i>len或j>len,则i=len或j=len

例如,[0:100:2]->范围(0,len(s),2)->范围(0,5,2)->0,2,4

如果i<0或j<0,则i=max(0,len(s)+i)或j=max

例如,[0:-3:2]->范围(0,len(s)-3,2)->范围(0,2,2)->0

例如,[0:-1:2]->范围(0,len(s)-1,2)->范围(0,4,2)->0,2

如果未指定i,则i=0

例如,[:4:2]->范围(0,4,2)->范围(4,2)->0,2

如果未指定j,则j=len(s)

例如,[0::2]->范围(0,len(s),2)->范围(0,5,2)->0,2,4


2.步骤<0。例如,[i:j:k](k<0)

假设序列为s=[1,2,3,4,5]。

如果0<i<len(s)和0<j<len,则[i:j:k]->范围(i,j,k)

例如,[5:0:-2]->范围(5,0,-2)->5,3,1

如果i>len或j>len,则i=len(s)-1或j=len(s)-1

例如,[100:0:-2]->范围(len(s)-1,0,-2)->范围(4,0,-2)->4,2

如果i<0或j<0,则i=max(-1,len(s)+i)或j=max(-1len(s)+j)

例如,[-2:-10:-2]->range(len(s)-2,-1,-2)->range(3,-1,-1)->3,1

如果未指定i,则i=len(s)-1

例如,[:0:-2]->范围(len(s)-1,0,-2)->范围(4,0,-2)->4,2

如果未指定j,则j=-1

例如,[2::-2]->范围(2,-1,-2)->2,0

例如,[::-1]->range(len(s)-1,-1,-1)->range(4,-1,1)->4,3,2,1,0


总而言之

我自己使用“元素之间的索引点”方法来思考它,但描述它的一种方式有时有助于其他人获得它:

mylist[X:Y]

X是所需的第一个元素的索引。Y是不需要的第一个元素的索引。

当我第一次看到切片语法时,有一些事情不是很明显:

>>> x = [1,2,3,4,5,6]
>>> x[::-1]
[6,5,4,3,2,1]

反转顺序的简单方法!

如果出于某种原因,您希望以相反的顺序进行每一项:

>>> x = [1,2,3,4,5,6]
>>> x[::-2]
[6,4,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的默认值。

已经有很多答案了,但我想添加一个性能比较

~$ python3.8 -m timeit -s 'fun = "this is fun;slicer = slice(0, 3)"' "fun_slice = fun[slicer]" 
10000000 loops, best of 5: 29.8 nsec per loop
~$ python3.8 -m timeit -s 'fun = "this is fun"' "fun_slice = fun[0:3]" 
10000000 loops, best of 5: 37.9 nsec per loop
~$ python3.8 -m timeit -s 'fun = "this is fun"' "fun_slice = fun[slice(0, 3)]" 
5000000 loops, best of 5: 68.7 nsec per loop
~$ python3.8 -m timeit -s 'fun = "this is fun"' "slicer = slice(0, 3)" 
5000000 loops, best of 5: 42.8 nsec per loop

因此,如果您重复使用同一个切片,使用切片对象将有益并提高可读性。然而,如果您只进行了几次切片,则应首选[:]表示法。