7 切片Slice
切片,是一个比较生疏的名词,这是现代计算机编程语言或者说Python里的一个概念,大致意思是从一个集合里切出一块来,就像切一块豆腐,一刀下去切出两块豆腐,问题是两刀能切出几块?开个小玩笑!
先看一个函数range、返回值是列表,内容和传入range的函数有关。
a = range(1, 21)
print a
结果
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
明白了,range可以产生从1到20共20个元素的列表,range的第二个参数不包含这个值,但包含第一个参数的值,每个元素值相差为1。
7.1 什么是切片
回到正题,切片是对有序的集合而言,意思从有序集合里提取数据构成子集集合,给定提取的起点start、终点end以及方向上的步长step,能否切出非空子集,起点start需能沿步长方向上到达终点。
字符串和列表、元组都是有序集合,均可实现切片操作,以列表为例给出切片的语法格式如下:
子集名 = 有序集合名[start : end : step]
上边range(1, 21)和切片里的start、end是呼应一致的,含起点start对应的值而不含终点end所对应的值。
step = 1
子集的构成是从start开始每step取一个数据一至到end-1位置结束,step默认为1时,可以省略不写。
s = "python"
a = list(s)
print a
b = a[2:5]
print b
程序的结果如下:
['p', 'y', 't', 'h', 'o', 'n']
['t', 'h', 'o']
0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
'p' | 'y' | 't' | 'h' | 'o' | 'n' |
从print b这条语句的打印结果['t', 'h', 'o']可知,'t'在a列表的index为2,'n'字符的index为5,那么a[2:5]的step为1,从't'开始逐个取回字符't'、'h'、'o'组成新的列表的子集b,而字符'n'的index为5,5作为取切片操作a[2:5]里的终点,其字符'n'不取回。从例子可以看出step 为1可以理解为“逐个取”。
step > 1
step可以大于1,这个时候对于step的理解可以这样认为,每step个取一个。
s = "python"
a = list(s)
print a
b = a[2:5:2]
print b
程序的结果如下:
['p', 'y', 't', 'h', 'o', 'n']
['t', 'o']
对于列表a取切片a[2 : 5 : 2], 从index为2开始,每2个元素为一组取每组的第一个数据值,一只到index为5结束,但不取index为5的数据。
a[2 : 5 : 2]具体操作是这样的,从index为2的字符't'开始,到index为5的字符'n'之前,每2个为一组('t', 'h')、('o', 'n')取每组的第一个元素值't'、'o'即结果子集b的值。
再看一个例子:
a = range(12)
print a
b = a[1 : 10 : 3]
print b
结果是:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
[1, 4, 7]
从两行输出结果的第一行可以看出range函数可以产生一个从0开始到小于12的整数的列表,共12个数据。
第二行的输出[1, 4, 7]是怎么产生的呢?这个和对a列表的切片操作有关,a[1 : 10 : 3],这里a[1:10] = [1, 2, 3, 4, 5, 6, 7, 8, 9],每3个一组,从每组取第一个,即 [1, 2, 3],[4, 5, 6], [7, 8, 9]这三组,取每组第一个1、4、7构成b这个子集,最后得到的b = [1, 4, 7]。
7.2 负索引和负方向
前章讲列表的时候提到了在python里有序集合的index位置信息可正可负,方向可以从左向右或从右向左。以“python”字符串通过list函数转化生成的列表为例,其正负位置信息index值如下所示:
0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
'p' | 'y' | 't' | 'h' | 'o' | 'n' |
-6 | -5 | -4 | -3 | -2 | -1 |
故,切片的start、end、step也可用负数来表示。
例1:
s = "python"
print s
a = list(s)
print a
b = a[1 : -2 : 1]
print b
c = a[1 : -2 : -1]
print c
程序的执行结果如下:
python
['p', 'y', 't', 'h', 'o', 'n']
['y', 't', 'h']
[]
为何c为空呢?
原因:从起点start开始如果step为正从左向右到达end进行切片操作,如果step为负从右向左到达end进行切片操作。对b起点在左方向向右是能到达终点的,而对于c那条切片语句a[1 : -2 : -1],起点在左方向向右是无法到达终点的故结果集为空。
例2
s = "python"
print s
a = list(s)
print a
b = a[-1 : 2 : 1]
print b
c = a[-1 : 2 : -1]
print c
程序的执行结果如下:
python
['p', 'y', 't', 'h', 'o', 'n']
[]
['n', 'o', 'h']
为何b为空呢?
对于b和c所对应的取切片操作的起点start = -1、终点end = 2,但取得b的切片操作的step = 1意思是从起点从左向右到达终点,不可能,因为终点在左边故b为空的列表集。而c所对应的取切片操作的方向是step = -1即从右向左是可以最终到达终点的,故得到['n', 'o', 'h']结果。
例3
对于字符串,有序的集合,也是可以使用切片的。有的时候切片操作的start和end以及step会没有指定,这个时候是一些特殊用法,通常暗含的意思是该方向上的首尾。
s = "python"
print s[:]
print s[::1]
print s[::-1]
print "*****"
print s[1::1]
print s[1::-1]
print "*****"
print s[:5]
print s[:3:1]
print s[:3:-1]
程序执行结果:
python
python
nohtyp
*****
ython
yp
*****
pytho
pyt
no
(1) s[:]切片,[:]即全切即列表本身,即首尾都要。
(2) s[::1]切片,正向全切,正向全切结果和s[:]一样
(3) s[::-1]切片,负向全切,等价于s[len(s)-1::-1]
(4)s[1::1]切片,从index为1开始到正方向尾部所有元素。
(5)s[1::-1]切片,从index为1开始一直沿负方向(右向左)到该方向尾部。
(6)s[:5]切片,正向切到index为5 - 1 = 4为止,起点默认为该方向的起点值0。
(7)s[:3:1]切片,明确指明了正向步长为1,正向切片的终点index为3,起点默认该方向的起点值0 。
(8)s[:3:-1]切片,负方向切片的终点为3,起点默认为该方向的起点值-n 。