切片就是在有序序列对象(字符串、元组或列表)中选择某个范围内的项。 切片可被用作表达式以及赋值或 del 语句的目标。
Python的有序序列对象可以用索引号来引用的元素的,索引号可以是正数由0开始从左向右,也可以是负数由-1开始从右向左。
以 a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 为例:
需注意的是有序序列对象某个索引位置返回的是一个元素,而切片操作返回是和被切片对象相同类型对象的副本。切片的返回结果是一个新的独立的序列。以列表为例,列表切片后得到的还是一个新的列表,占用新的内存地址。② 切片是取操作,不改变原值。③ 切片的返回结果类型和切片对象类型一致,返回的是切片对象的子序列。如:对一个列表切片返回一个列表;字符串切片返回字符串。【如果被切片的对象是可变的序列对象,并且切片表达式在等号 = 的左侧,就可以直接更改原可变序列对象的值。如果切片表达式在等号 = 的右侧,那么返回的就是新的独立的序列对象副本。被切片对象是不可变的序列对象,只能处于等号= 的右侧,返回被切片对象的子序列副本。】
被切片对象不是可变对象,拷贝的是值;被切片对象是可变对象,是该可变元素的引用,共用一个空间。对于列表切片只是浅拷贝,它拷贝的是原列表中的引用。④ 切片生成的子序列元素是源版的拷贝,因此切片是一种浅拷贝。
切片操作的基本表达式:
object[start_index:end_index:step]
- start:切片的起始位置,如果没有值的话从头开始。
- end:切片的结束位置,但不包含end(前闭后开),如果没有值的话表示切割到结束为止。
- step:步长,默认取值为1,如果步长为正数的情况表示从左往右,反正若为负数则表示从右往左。step 的正负决定切的方向,这一点需要尤为注意!!!
注意:这些值都可以大于列表的长度,不会报越界。但是会发生截断,就是仍然按照范围查找,但是超出序列数据范围部分,全部被遐想成空值,最终获取到空值进行忽略即可。
被切片序列返回的子序列长度 count = end - start
切片并非列表的专属操作,但是因为列表最具代表性,下面主要以列表来举例。
均以列表 >>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 为例。
切割(取)完整对象:
>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[:] ## 单独一个冒号,代表从头取到尾,步长默认为1
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[::] ## 单独两个冒号一样代表从头取到尾,步长默认为1
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[::-1]##注意,两个冒号后面是步长,步长为1,故应从右往左取
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
切片中的三个参数为表达式:
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[1+2:2*3:7%2] ## 思路一样,运算出来,继续切
[3, 4, 5]
取偶数位置:
>>>b = a[::2]
[0, 2, 4, 6, 8]
取奇数位置:
>>>b = a[1::2]
[1, 3, 5, 7, 9]
切取单个值:
>>> a[0]
0
>>> a[-4]
6
修改单个元素:(是切片的应用吗?)
>>>a[3] = ['A','B']
[0, 1, 2, ['A', 'B'], 4, 5, 6, 7, 8, 9]
替换一部分元素:(是原先的 a 吗?)
>>>a[3:6] = ['A','B'] # [3:6]==[3,4,5],所以将3-5的索引的值替换成A、B
[0, 1, 2, 'A', 'B', 6, 7, 8, 9]
在某个位置插上元素:
>>>a[3:3] = ['A','B','C'] # [3:3] == [] ,所以在3之前直接插入数值
[0, 1, 2, 'A', 'B', 'C', 3, 4, 5, 6, 7, 8, 9]
>>>a[0:0] = ['A','B'] # 同理,在0之前插入数值
['A', 'B', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
拷贝整个对象:
>>>b = a[:]
>>>print(b) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>print(id(a)) # 41946376
>>>print(id(b)) # 41921864
>>>b = a.copy()
>>>print(b) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>print(id(a)) # 39783752
>>>print(id(b)) # 39759176
需要注意的是:[:]和.copy()都属于“浅拷贝”,只拷贝最外层元素,内层嵌套元素则通过引用,而不是独立分配内存。
>>>a = [1,2,['A','B']]
>>>print('a={}'.format(a))
a=[1, 2, ['A', 'B']] # 原始a
>>>b = a[:]
>>>b[0] = 9 # 修改b的最外层元素,将1变成9
>>>b[2][0] = 'D' # 修改b的内嵌层元素
>>>print('a={}'.format(a)) # b修改内部元素A为D后,a中的A也变成了D,说明共享内部嵌套元素,但外部元素1没变。
a=[1, 2, ['D', 'B']]
>>>print('b={}'.format(b)) # 修改后的b
b=[9, 2, ['D', 'B']]
>>>print('id(a)={}'.format(id(a)))
id(a)=38669128
>>>print('id(b)={}'.format(id(b)))
id(b)=38669192
连续切片操作:
>>>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 # [-1:] = [-1] 即:取最后一个值
理论上可无限次连续切片操作,只要上一次返回的依然是非空可切片对象。