前言
提示:这里可以添加本文要记录的大概内容:
利用python解决问题的过程中,经常会遇到从某个对象中抽取部分值的情况。“切片”操作正是专门用于实现这一目标的有力武器。理论上,只要条件表达式得当,可以通过单次或多次切片操作实现任意目标值切取。
切片操作的基本语法比较简单,但如果不彻底搞清楚内在逻辑,也极容易产生错误,而且这种错误有时隐蔽得较深,难以察觉。
切片操作不会因为下标越界而抛出异常,而是简单地在列表尾部截断或者返回一个空列表,代码具有更强的健壮性。
切片是Python序列的重要操作之一,适用于列表、元组、字符串、range对象等类型。本节课以列表类型作为讲解的对象,其结论可推广至其他可切片对象。
可以使用切片来截取列表中的任何部分,得到一个新列表。
提示:以下是本篇文章正文内容,下面案例可供参考
一、切片操作
Python切片操作的一般方式:object[start_index:end_index:step]
一个完整的切片表达式包含两个":",用于分隔三个参数(start_index、end_index、step)。
第一个数字表示切片开始位置(默认为0)
第二个数字表示切片截止(但不包含)位置(默认为列表长度)
第三个数字表示切片的步长(默认为1),当步长省略时可以顺便省略最后一个冒号。
当只有一个":" 时,默认第三个参数step=1;例如:a[1:3]
当一个":"也没有时,表示切取start_index指定的那个元素。
相当于取指定位置的值。
例如:a[2]
Python切片操作的一般方式:
step:正负数均可,其绝对值大小决定了切取数据时的‘‘步长”,而正负号决定了“切取方向”,正表示“从左往右”取值,负表示“从右往左”取值。当step省略时,默认为1,即从左往右以步长1取值。
切取方向非常重要!
start_index:表示起始索引(包含该索引对应值);该参数省略时,表示从对象“端点”开始取值,至于是从“起点”还是从“终点”开始,则由step参数的正负决定,step为正从“起点”开始,为负从“终点”开始。
end_index:表示终止索引(不包含该索引对应值);该参数省略时,表示一直取到数据“端点”,至于是到“起点”还是到“终点”,同样由step参数的正负决定,step为正时直到“终点”,为负时直到“起点”。
切取单个元素
代码如下(示例):
首先,定义一个列表如下
>>>a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
当索引只有一个数时,表示切取某一个元素。
>>>a[0]
>>>0
>>>a[-4]
>>>6
注意:
虽然切片操作不会因为下标越界而抛出异常,但是切单个元素的情况需要注意,还是会报异常。
>>> a[-100]
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
a[-100]
IndexError: list index out of range
>>> a[0:100:1] #前100个元素,自动截断
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[100:] #下标100之后的所有元素,自动截断
[]
切取完整对象
正序
>>>a[:] #从左往右
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>a[::]#从左往右
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
逆序
>>>a[::-1]#从右往左
>>> [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
start_index和end_index全为正(+)索引的情况
>>>a[1:6]
>>>[1,2,3,4,5]
step = 1,从左往右取值,start_index = 1 到 end_index=6 同样表示从左往右取值
>>>a[1:6:-1]
>>>>[]
输出为空列表说明没有取到数据
step = -1,决定了从右往左取值,而start_index=1 到 end_index=6决定了从左往右取值
两者矛盾所以为空
>>>a[6:2]
>>>[]
同样输出为空列表
step=1,决定了从左往右取值
而start_index=6 到 end_index=2 决定了从右往左取值,两者矛盾所以为空
>>>a[:6]
>>>[0,1,2,3,4,5]
step=1,表示从左往右取值,而 start_index 省略时,表示从端点开始,
因此这里的端点是 “起点”,即从 “起点” 值 0 开始一直取到 end_index=6 (该点不包括)
>>>a[6:]
>>>[6,7,8,9]
step = 1,从左往右取值,从 start_index=6开始,一直取到 “终点” 值9
>>>a[6::-1]
>>>[6,5,4,3,2,1,0]
step=1,从右往左取值,从start_index=6开始,一直取到 “起点” 值0
start_index和end_index全为负(-)索引的情况
>>>a[-1:6]
>>>[]
step=1,从左往右取值,而start_index= -1 到 end_index= -6 决定了从右往左取值
两者矛盾,所以为空
索引 -1 在 -6 右边
>>>a[-1:-6:-1]
>>>[9,8,7,6,5]
step = -1,从右往左取值,start_index = -1 到 end_index = -6 同样是从右往左取值
索引 -1 在 6 右边
>>>a[-6:-1]
>>>[4,5,6,7,8]
step=1,从左往右取值,而start_index = -6 到 end_index = -1 同样是从左往右取值
索引 -6 在 -1 左边
>>>a[:-6]
>>>[0,1,2,3]
step=1,从左往右取值,从"起点" 开始一直取到 end_index = -6 (该点不包括)
>>>a[:-6:-1]
>>>[9,8,7,6,5]
step = -1,从右往左取值,从"终点" 开始一直取到 end_index = -6 (该点不包括)
>>>a[-6:]
>>>[4,5,6,7,8,9]
step=1,从左往右取值,从start_index = -6 开始,一直取到 " 终点"
>>>a[-6::-1]
>>>[4,3,2,1,0]
step = -1,从右往左取值,从start_index = -6 开始,一直取到 “起点”
start_index和end_index正(+)负(-)混合索引的情况
>>>a[1:6]
>>>[1,2,3]
start_index=1 在 end_index = -6 左边,因此从左往右取值
step=1 同样决定了从左往右取值,因此结果正确
>>>a[1:-6:-1]
>>>[]
start_index=1 在 end_index = -6 的左边,因此从左往右取值,但step = -1 则决定;从右往左取值。
两者矛盾,因此为空
>>>a[-1:6]
>>>[]
start_index = -1 在 end_index=6 的右边,因此从右往左取值
但step=1 则决定了从左往右取值,两者矛盾,因此为空
>>>a[-1:6:-1]
>>>[9,8,7]
start_index= -1 在 end_index=6 的右边,因此从右往左取值,而step = -1
同样决定了从右往左取值,因此结果正确
多层切片操作
>>>a[:8][2:5][-1:]
>>> [4]
相当于:
a[:8]=[0, 1, 2, 3, 4, 5, 6, 7]
a[:8][2:5]= [2, 3, 4]
a[:8][2:5][-1:] = [4]
理论上可无限次多层切片操作,只要上一次返回的是非空可切片对象即可。
切片操作的三个参数可以用表达式
>>>a[2+1:3*2:7%3]
>>> [3, 4, 5]
即:a[2+1:3*2:7%3] = a[3:6:1]
二、Python切片一些常用操作
>>>a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
取偶数位置
>>>b = a[::2]
[0, 2, 4, 6, 8]
取奇数位置
>>>b = a[1::2]
[1, 3, 5, 7, 9]
拷贝整个对象
>>>b = a[:]
>>> b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> id(a)
2670565854152
>>> id(b)
2670566271112
或
>>> c=a.copy()
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> id(a)
2670565854152
>>> id(c)
2670565953416
需要注意的是:[:]和.copy()都属于“浅复制”,只复制最外层元素,内层嵌套元素则通过引用方式共享,而非独立分配内存
所谓浅复制,是指生成一个新的列表,并且把原列表中所有元素的引用都复制到新列表中。如果原列表中只包含整数、实数、复数等基本类型或元组、字符串这样的不可变类型的数据,一般是没有问题的。如果原列表中包含列表之类的可变数据类型,由于浅复制时只是把子列表的引用复制到新列表中,这样的话修改任何一个都会影响另外一个。
只拷贝最外层元素,内层嵌套元素则通过引用方式共享,而非独立分配内存。
如果要 “深复制” 该如何写?
>>> import copy # 引入 copy 库
>>> a = [3, 5, 7,['x', 'y']]
>>> b = copy.deepcopy(a) # 调用 copy 库中的 deepcopy 函数
>>> a
[3, 5, 7, ['x', 'y']]
>>> b
[3, 5, 7, ['x', 'y']]
>>> a[3][1] = 'abc'
>>> a
[3, 5, 7, ['x', 'abc']]
>>> b # 这下怎么折腾都不会影响到 b 了
[3, 5, 7, ['x', 'y']]
三、使用切片来原地修改列表内容
增加和修改列表元素列表元素
>>> aList = [3, 5, 7]
>>> aList[len(aList):] = [9] #在尾部追加元素
>>> aList
[3, 5, 7, 9]
>>> aList[:3] = [1, 2, 3] #替换前3个元素
>>> aList
[1, 2, 3, 9]
>>> aList[:3] = [] #通过修改的方式删除前3个元素
>>> aList
[9]
>>> aList = list(range(10))
>>> aList
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> aList[::2] = [0]*5 #替换偶数位置上的元素
>>> aList
[0, 1, 0, 3, 0, 5, 0, 7, 0, 9]
>>> aList[::2] = [0]*3 #切片不连续,两个元素个数必须一样多
ValueError: attempt to assign sequence of size 3 to extended slice of size 5
使用del与切片结合来删除列表元素
>>> aList = [3,5,7,9,11]
>>> del aList[:3] #删除前3个元素
>>> aList
[9, 11]
>>> aList = [3,5,7,9,11]
>>> del aList[::2] #删除偶数位置上的元素
>>> aList
[5, 9]
使用列表对象的sort方法进行原地排序,支持多种不同的排序方法
>>> aList = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> import random
>>> random.shuffle(aList)
>>> aList
[3, 4, 15, 11, 9, 17, 13, 6, 7, 5]
>>> aList.sort() #默认是升序排序
>>> aList.sort(reverse = True) #降序排序
>>> aList
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]
>>> aList.sort(key = lambda x:len(str(x))) #按转换成字符串的长度排序
>>> aList
[9, 7, 6, 5, 4, 3, 17, 15, 13, 11]
使用内置函数sorted()对列表进行排序并返回新列表
>>> aList
[9, 7, 6, 5, 4, 3, 17, 15, 13, 11]
>>> sorted(aList) #升序排序
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> sorted(aList,reverse = True) #降序排序
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]
与sort()区别是,sorted()返回一个新列表,并不对原列表进行任何修改。
使用列表对象的reverse方法将元素原地逆序
>>> aList = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> aList.reverse()
>>> aList
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]
四、总结
切片概念和一般操作
1、切取单个元素
2、切取完整对象
3、start index 和 lend index 全为正(+)索引的情况
4、start index 和 lend index 全为负(-)索引的情况
5、start index 和 end index 正(+)负(-)混合索引的情况
6、多层切片操作
7、切片操作的三个参数可以用表达式
8、其他对象的切片操作
切片常用操作
1、取偶数位置
2、取奇数位置
3、拷贝整个对象,浅复制和深复制
4、使用切片来原地修改列表内容
5、列表排序
正序、倒序
文章出处登录后可见!