目录
13、通过带星号的 unpacking 操作来捕获多个元素,不要用切片
14、用 sort 方法的 key 参数来表示复杂的逻辑排序
11、学会对序列做切片
- 凡是实现了 __getitem__ 与 __setitem__ 这两个特殊方法的类都可以切割。
- 开始省略下标0,结束省略结尾下标,负数下标表示倒数。
- 如果起点、终点越界,会自动忽略不存在的元素,很容易构造出最多只有若干元素的序列。
- 切割出来的列表是一份全新的列表,即便把某个元素换掉,也不会影响原列表中相应位置。
- 切片可以出现在赋值符号左侧,表示用右侧那些元素把原列表中这个范围内元素换掉。不要求等号两边所指定的元素个数必须相同。原列表中,位于切片范围之前和之后的那些元素会予以保留,但是列表的长度可能有所变化。
- 起点、终点位置都留空的切片,出现在赋值符号右侧,表示给列表做副本。内容相同,身份却不同。
- 把不带起点、终点的切片放在赋值符号左边,表示用右边列表的副本把左侧列表全部内容替换掉。
a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
b = a[3:]
print('Before: ', b)
b[1] = 99
print('After: ', b)
print('No change: ', a)
------------------------------------------------
>>> Before: ['d', 'e', 'f', 'g', 'h']
After: ['d', 99, 'f', 'g', 'h']
No change: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
print('Before: ', a)
a[2:7] = [99, 22, 14]
print('After: ', a)
a[2:3] = [47, 11]
print('After: ', a)
-------------------------
>>> Before: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
After: ['a', 'b', 99, 22, 14, 'h']
After: ['a', 'b', 47, 11, 22, 14, 'h']
b = a
print('Before a', a)
print('Before b', b)
a[:] = [101, 102, 103]
print('After a', a)
print('After b', b)
-------------------------
>>> Before a ['a', 'b', 47, 11, 22, 14, 'h']
Before b ['a', 'b', 47, 11, 22, 14, 'h']
After a [101, 102, 103]
After b [101, 102, 103]
12、不要在切片里同时指定起止下标与步进
- 列表、bytes 类型的字符串、Unicode 形式的字符串可以用步进 -1 来反转;UTF-8 字符串不能用这个技巧反转。
- 同时使用起止下标与步进会让切片很难懂。如果必须指定步进,尽量采用正数,而且要把起止下标都留空。
- 即便必须同时使用步进值与起止下标,也应该考虑分成两次来写。
- 先隔位选取,然后再切割,会让程序多做一次浅拷贝,所以应该把最能缩减列表长度的那个切片操作放在前面。
y = x[::2]
z = y[1:-1]
13、通过带星号的 unpacking 操作来捕获多个元素,不要用切片
- 这种写法至少要有一个普通的接受变量与它搭配,否则就会出现语法错误。不能只使用带星号的表达式而不搭配普通变量。
- 对于单层结构来说,同一级里面最多只能出现一次带星号的 unpacking。
- 带星号的表达式会形成一份0个或多个值的列表实例(有可能耗尽计算机的全部内存并导致程序崩溃,首先必须确定系统有足够的内存可以存储拆分出来的结果数据),如果拆分的序列里已经没有元素留给它了,列表就是空白的。
car_ages_descending = [20, 19, 15, 9, 8, 7, 6, 4, 1, 0]
oldest, second_oldest, *others = car_ages_descending
print(oldest, second_oldest, others)
------------------------------------------------------------
>>> 20 19 [15, 9, 8, 7, 6, 4, 1, 0]
car_ages_descending = [20, 19, 15, 9, 8, 7, 6, 4, 1, 0]
oldest, *others, youngest = car_ages_descending
print(oldest, youngest, others)
------------------------------------------------------------
>>> 20 0 [19, 15, 9, 8, 7, 6, 4, 1]
car_ages_descending = [20, 19, 15, 9, 8, 7, 6, 4, 1, 0]
*others, second_youngest, youngest = car_ages_descending
print(youngest, second_youngest, others)
------------------------------------------------------------
>>> 0 1 [20, 19, 15, 9, 8, 7, 6, 4]
14、用 sort 方法的 key 参数来表示复杂的逻辑排序
- list 类型的 sort 方法总是按照自然升序排列列表内的元素。
- 可以把排序逻辑定义成函数,然后将这个函数传递给 sort 方法的 key 参数。(key 函数本身应该带有一个参数,指代列表中有待排序的对象,函数返回的应该是个可比较的值)
- 排序时依据的指标有很多项,可以放在一个元组中,元组之间是可以比较的,依次比较每个位置的两个对应元素,直到能够确定大小为止。
- 如果在某一指标上采用“-”可以实现按逆序排序。
- sort 方法的一项特征:稳定的排序算法,如果 key 函数认定两个值相等,这两个值在排序结果中的先后顺序会与它们在排序前的顺序一致。可以在同一个列表上多次调用 sort 方法,每次指定不同的排序指标,指定 key 函数和 reverse 参数。把首要指标放在第二轮,次要指标放在第一轮。无论有多少项排序指标都可以按照这种思路来实现,而且每项指标可以分别按照各自的方向来排,不用全部是升序或降序。最重要的排序指标放在最后一轮处理。(只有迫不得已的时候,才考虑多次调用 sort 方法)
tools.sort(key=lambda x: x.name)
tools.sort(key=lambda x: x.weight)
# 以下两种方式会让 weight 和 name 均按同样方向排序
tools.sort(key=lambda x: (x.weight, x.name))
tools.sort(key=lambda x: (x.weight, x.name), reverse=True))
# 利用-进行逆序排序,但是name这种str不支持-运算符
tools.sort(key=lambda x: (-x.weight, x.name))