Python提供了一种把序列切成小块的操作,称为切片(slice)操作,其本质是访问由序列中的某些元素所构成的子集。Python的序列数据结构都支持切片操作,如列表、元组、字符串等,切片操作可以说是日常应用中最常使用的Python特性之一。
(1)基本写法
sequence[start : end]
sequence:表示序列,可以是列表、字符串、元组等;
start:起始索引;
end:结束索引。
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = a[0:5]
c = a[:]
d = a[5:15]
print('a=', a, 'b=', b, 'c=', c, 'd=', d)
可以看出:输出结果:a= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]b= [1, 2, 3, 4, 5]c= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]d= [6, 7, 8, 9, 10]
1)序列a没有变化,说明切片(slice)操作不改变原序列,而是生成一个新序列;
2)序列b的结果说明从头切片的话,索引值是从0开始的,另外start所指元素在切片结果内,而end所指元素则不包括在切片结果中,说明切片[start:end]是一个半闭区间;
3)序列c结果说明从头切片的话,start索引值0可以省略,如果取到序列末尾,end也应该省略,这样更清爽;
4)序列d结果说明索引范围不能越过序列本身边界,越过边界自动取边界值(Python3特性,在Python2会报错)。
(2)负值索引
若要从序列尾部向前算,则可以用负值表示相关偏移量。
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = a[:-1]
c = a[-3:]
print('b=', b, 'c=', c)
输出结果:b= [1, 2, 3, 4, 5, 6, 7, 8, 9]c= [8, 9, 10]
可以看出:
1)序列b比a少了最后一个元素,说明:-1表示最后一个元素;
2)序列c结果表明:用-n代表倒数第n个元素,并且即使start索引是负数,切片顺序也是从前往后的。
(3)反向和步进操作
除了基本写法外,Python还提供了sequence[start : end : stride]的写法,以实现步进式切割。看示例:
s = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a = s[::2]
b = s[::-1]
c = s[::-2]
print('a=', a, 'b=', b, 'c=', c)
输出结果:a= [1, 3, 5, 7, 9]b= [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]c= [10, 8, 6, 4, 2]
可以看出:
1)序列a为序列s每隔2个元素进行取值,说明有stride的话按步进值间隔取序列中的元素;
2)序列b与序列s为反向,说明步进值为负值的话,实施的是反向操作,从序列末尾从后往前取元素。
3)序列c的结果说明使用负数布进值,除了按照反向操作外,也按照数字大小间隔取元素。
一般的应用情况下,与正向切片相比,反向切片和步进操作使用相对较少,但需要用的话,是非常好用且异常简洁的。看一个反向操作的经典应用:回文字符串判断
,
回文字符串是指aba、abba、cccbccc、aaaa这种左右对称的字符串。
先看C语言的经典实现:
bool fun(char str[])再看Python中利用反向切片操作的实现,异常简洁:
{
int i, j, n;
n = strlen(str);
for (i = 0, j = n-1; i <= (n-1)/2; i++, j--)
{
if (str[i] != str[j])
break;
}
if i > j
return True;
else
return False;
}
def fun(str):
return str == str[::-1]
s = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a = s[-2:2:-2]
print(a)
输出结果:a= [9, 7, 5]
改进方式可以考虑使用两条赋值语句代替,具体方法可是先做范围切片,再做步进切片,也可以先做步进切片,再做范围切片。个人认为先范围再步进的方法更好。
s = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a = s[-2:2:-2]
b = s[3:len(s)-1]
c = b[::-2]
print('a=', a, 'c=', c)
输出结果:a= [9, 7, 5]c= [9, 7, 5]
实际工作中如果思路清晰,切片使用熟练,同时指定start,end和stride也无不妥,毕竟就3个参数而已。