深入讨论Python中的序列切片语法

本小节深入探讨Python中的序列切片语法。
切片-slicing可以获取序列的子序列(列表,字符串…):

numbers = [x for x in range(10)]
print("numbers:",numbers)
print("numbers[3:9]:",numbers[3:9])
print("numbers[3:]:",numbers[3:])
print("numbers[:9]:",numbers[:9])
print("numbers[-6:-1]:",numbers[-6:-1])
print("numbers[1:9:2]:",numbers[1:9:2])
print("numbers[-1:1:-2]:",numbers[-1:1:-2])

版权声明

本文可以在互联网上自由转载,但必须:注明出处(作者:海洋饼干叔叔)并包含指向本页面的链接。

本文不可以以纸质出版为目的进行改编、摘抄。

本文节选自作者的《Python编程基础及应用》视频教程。

切片

切片-slicing可以获取序列的子序列(列表,字符串…):

numbers = [x for x in range(10)]
print("numbers:",numbers)
print("numbers[3:9]:",numbers[3:9])
print("numbers[3:]:",numbers[3:])
print("numbers[:9]:",numbers[:9])
print("numbers[-6:-1]:",numbers[-6:-1])
print("numbers[1:9:2]:",numbers[1:9:2])
print("numbers[-1:1:-2]:",numbers[-1:1:-2])

执行结果:

numbers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
numbers[3:9]: [3, 4, 5, 6, 7, 8]
numbers[3:]: [3, 4, 5, 6, 7, 8, 9]
numbers[:9]: [0, 1, 2, 3, 4, 5, 6, 7, 8]
numbers[-6:-1]: [4, 5, 6, 7, 8]
numbers[1:9:2]: [1, 3, 5, 7]
numbers[-1:1:-2]: [9, 7, 5, 3]
说明
- 切片功能强大到令人发挥的程度,同时也复杂到令人费解;
- numbers[3:9]从下标3开始复制元素,直到下标8(9-1);
- numbers[3:]等价于numbers[3:10],从下标3开始复制元素,直到末尾,即下标9(10-1);
- numbers[:9]等价于numbers[0:9],从下标0开始复制元素,直到下标8(9-1);
- numbers[-6:-1]等价于numbers[4:9],其中len(numbers)-6=4, len(numbers)-1=9;
- numbers[1:9:2]从下标1开始复制元素,每复制1个元素,下标+2, 直到下标达到或超过9结束(注意不包括下标为9的元素);
- numbers[-1:1:-2]从下标len(numbers)-1,即下标9开始复制元素,每复制1个元素,下标-2,直到下标<=1结束(注意不包括下标为1的元素)。

​ 综上,numbers的切片的完整形式为: numbers[x:y:z],z为步长,缺省值为1,x为起始下标,y为终止下标。z > 0时,x缺省为0, 包括最左端的元素, y缺省为len(numbers),包括最右端的元素,最右端元素的下标为len(numbers)-1。注意,当z值为负数时,切片方向为从右往左,起始下标x应包括最右方(也就是最后一个)元素,故x的缺省值为len(numbers)-1;终止下标y则为-1, 这有点让有费解:因为如果y为0的话,列表的下标0元素将不会被包括在切片中。如果你还感到疑惑,请看下一小节。

深入理解切片

​ 切片的过程事实上跟数值列表range(x,y,z)的计数过程十分类似,由于这个切片过程适用于所有序列(字符串,列表…),故下图中我们用seq[x:y:z]表示序列及其切片参数,首先考虑z>0的情况:
在这里插入图片描述

​ 现以numbers[1:9:2]为例,依上述流程图说明输出集合为什么是[1,3,5,7]。首先,下标取值x=1,然后开始循环:

- 下标1 < 9成立,复制numbers[1],即值1; 
- 下标=1+2=3; 
- 下标3 < 9成立,复制numbers[3],即值3; 
- 下标=3+2=5; 
- 下标5 < 9成立,复制numbers[5],即值5;
- 下标=5+2=7; 
- 下标7 < 9成立,复制numbers[7],即值7;
- 下标=7+2=9; 
- 下标9 < 9不成立,循环结束。

​ 如果你有C/C++经验,看下面的代码秒懂,因为Python的解释器就是用C/C++编写的。

for (int i=x;i<y;i+=z){
    copy(seq[i]);
}

​ 当z<0时,seq[x:y:z]的切片流程图如下:
在这里插入图片描述

​ 当z<0时,切片过程事实上是从序列尾部往头部方向行进的,由于z是负数,所以下标=下标+z事实上导致下标减小。如果你有C/C++经验,看下面的代码秒懂,因为Python的解释器就是用C/C++编写的。

for (int i=x;i>y;i+=z){
    copy(seq[i]);
}

​ **该你了,请依上述流程图,人肉执行numbers[-1:1:-2]的切片过程,看看输出结果跟Python解释器输出是否一致。**提示,-1表示倒数第1个元素,即len(numbers)-1=9。

妙用切片

numbers = [x for x in range(10)]
numbersCopy = numbers[:]
print("id:", id(numbers), numbers)
print("id:", id(numbersCopy), numbersCopy)

numbersReversed = numbers[::-1]
print("numbersReversed:",numbersReversed)

numbers[3:5] = 77,88
print("numbers:",numbers)

执行结果:

id: 2611651371592 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
id: 2611651371656 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
numbersReversed: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
numbers: [0, 1, 2, 77, 88, 5, 6, 7, 8, 9]

​ 从上述代码及执行结果可以看出,numbers[:]产生了numbers的副本,其效果等价于numbers.copy(), numbers与numbersCopy的id值不同;而numbers[::-1]从尾部往前进行切片,其切片正好将序列倒序。这与numbers.reverse()有区别,numbers.reverse()会导致numbers列表被改变,且不会返回新列表;而numbers[::-1]会保持numbers列表不变,并生成一个新的列表。

​ 请注意倒数第二行代码,对列表的切片还可以用于批量修改列表元素。从结果可见,numbers[3:5] = 77,88等价于numbers[3] = 77和numbers[4] = 88。

字符串切片

​ 作为一种序列,字符串的切片方法与列表几乎完全相同,见下述代码:

numbers = '0123456789'
print(numbers[2:5])
print(numbers[1:9:2])
print(numbers[:3:-2])

执行结果:

234
1357
975

本文节选自作者的《Python编程基础及应用》视频教程。想完整零基础学习Python程序设计,欢迎使用此免费视频教程。

发布了29 篇原创文章 · 获赞 0 · 访问量 140

猜你喜欢

转载自blog.csdn.net/SeaBiscuitUncle/article/details/103941588