深入理解切片原理

通过指定下标的方式来获得某一个数据元素,或者通过指定下标范围来获得一组序列的元素,这种访问序列的方式叫做切片。有些地方也把它称之为分片。

关于切片的工作方式,可以参考我之前写的文章:Python中切片的工作原理

先从底层分析切片运算:
list的切片,内部是调用__getitem__,__setitem__,__delitem__和slice函数。而slice函数又是和range()函数相关的。
给切片传递的键是一个特殊的slice对象。该对象拥有可描述所请求切片方位的属性,
例如:

a = [1,2,3,4,5,6]
x = a [ 1 : 5 ]                # x = a.__getitem__(slice( 1, 5, None))
a [ 1 : 3 ] = [10, 11, 12 ]    # a.__setitem__(slice(1, 3, None), [ 10, 11, 12 ])
del a [ 1 : 4 ]                # a.__delitem__(slice(1, 4, None))


切片操作的方法:con[start_index:end_index:step]
start_index:表示是第一个元素对象,正索引位置默认为0;负索引位置默认为 -len(con)
end_index: 表示是最后一个元素对象,正索引位置默认为 len(con)-1;负索引位置默认为-1。
step: 表示取值的步长,默认为1,步长值不能为0。
对于序列来说,索引和步长都具有正负两个值,分别表示左右两个方向取值。索引的正方向从左往右取值,起始位置为0;负方向从右往左取值,起始位置为-1。
因此任意一个序列结构数据的索引范围为-len(con)到len(con)-1范围内的连续整数。

切片的操作类型
con[start_index]:返回索引值为start_index的对象。start_index为-len(con)到len(con)-1之间任意整数。
con[start_index:end_index]:返回索引值为start_index到end_index-1之间的连续对象。
con[start_index:end_index:step]:返回索引值为start_index到end_index-1之间,并且索引值与start_index之差可以被step整除的连续对象。

con[start_index:]:缺省end_index,表示从start_index开始到序列中最后一个对象。
con[:end_index]:缺省start_index,表示从序列中第一个对象到end_index-1之间的片段。
con[:]:缺省start_index和end_index,表示从第一个对象到最后一个对象的完整片段。
con[::step]:缺省start_index和end_index,表示对整个序列按照索引可以被step整除的规则取值。

切片的用法

#1.step取值相关案例
>>> lst = range(10)
>>> lst
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

#案例1
>>> lst[::1]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> lst[0:len(lst)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> lst
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> lst[-len(lst):-1].append(lst[9])
>>> lst
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

#案例2
>>> lst[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> lst[-1:-10:-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1]

#案例3
>>> lst[-1:1]
[]
>>> lst[-1:1:1]
[]
lst[-1:1]等价于lst[-1:1:1],由于最后一个元素后面找不到index为1的,故返回为空。

#案例4
>>> lst[-1:1:-1]
[9, 8, 7, 6, 5, 4, 3, 2]
从下标为-1的元素开始,以反方向切片找到到index为1的元素(即2)。
等价于:lst[-1:-len(lst)+1:-1]
>>> lst[-1:-9:-1]
[9, 8, 7, 6, 5, 4, 3, 2]

#2.start_index和end_index取值相关案例
>>> lst = [1,2,3,4,5,6]   #lst上界为0,下界为6
>>> lst[-10:10]           #-10超出了上界,10超出了下界,等价于lst[0:6],返回[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]
>>> lst[-10:-20]          #-10和-20均超出了上界,自动取上界,等价于lst[0:0],返回[]
[]
>>> lst[10:20]            #10和20均超出了下界,自动取下界,等价于lst[6:6],返回[]
[]
>>> lst[:100]             #start缺省:表示从第0个开始,返回[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]
>>> lst[0:]               #end缺省:表示从start位置取到结尾,返回[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]

#3.start_index:end_index:step综合案例
>>> lst = range(100)
>>> lst[:10]                                #取前10个数
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> lst[-10:]                               #取后10个数
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]    
>>> lst[10:20]                              #取第11-20个数
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]    
>>> lst[:20:2]                              #取前20个数,每隔2个取1个
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> lst[::5]                                #取所有数,每隔5个取1个
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
>>> lst[:]                                  #什么都不写,表示按原样复制list
[0, 1, 2, 3, 4, 5, 6。。。, 98, 99]
>>> lst[::]                                 #什么都不写,表示按原样复制list
[0, 1, 2, 3, 4, 5, 6。。。, 98, 99]

#利用range函数生成1-100的数,取3的倍数,并且取前十个
>>> [i for i in range(1,100)[2::3][:10]]
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30]

#利用range函数生成1-100的数,取3的倍数,并且取最后十个
>>> [i for i in range(1,100)[2::3][-10:]]
[72, 75, 78, 81, 84, 87, 90, 93, 96, 99]

#从range(1,100)中取7的倍数
>>> [x for x in range(1,100)[6::7]]
[7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98]

相对reverse而言,切片的方法不会改变列表的结构,所以这是在实际应用中比较有用的一个技巧。

参考文献:
彻底理解Python切片:https://www.cnblogs.com/weidiao/p/6428681.html
Python中切片的理解:http://blog.csdn.net/u011242657/article/details/56289429

原文地址:https://www.cnblogs.com/huangbiquan/p/7900901.html