fluentpython第⼆版_流畅的python,FluentPython第⼆章笔记2.1内置序列类型的概览
Python标准库⽤C实现了丰富的序列类型
容器序列
list,tuple和collections.deque这些序列都能存放不同的数据类型。
扁平序列
str,bytes,bytearray,memoryview,array.array,这种序列只能容纳⼀种类型。
容器徐蕾存放的是他们所包含的任意类型的对象的引⽤,⽽扁平序列⾥存放的是值⽽不是引⽤。
不可变序列 (Sequence)
tuple、str、bytes
剩下的都是可变的 (MutableSequence)
2.2列表推导和⽣成器表达式
列表推导,我已经讲了多次,使⽤相对熟练,跳过。
⽣成器表达式与列表表达式在使⽤中,⼀个最⼤的好处,假如被for循环遍历,如果数据很⼤,⽤⽣成器表达式可以省下⽣成列表的开销。
2.3元祖不仅仅是不可变的列表
主要介绍了元祖的拆包赋值,已经*的使⽤。
In [88]: a,b,*rest = range(5)
In [89]: a,b,rest
Out[89]: (0, 1, [2, 3, 4])
In [90]: a,*body,c,d = range(10)
In [91]: a,body,c,d
Out[91]: (0, [1, 2, 3, 4, 5, 6, 7], 8, 9)
⽤起来还是很有意思的。
nametuple前⾯我已经介绍过了,不写笔记了,多本书上介绍,看来还是蛮重要的。
说明⼀点,nametuple构建的类的实例所消耗的内存跟元祖⼀样,因为不会⽤__dict__来存放这些实例的属性。
2.4切⽚
主要讲述了对对象进⾏切⽚,slice与切⽚赋值,切⽚赋值的对象⼀定要是可迭代对象
invoice = '''
<6...........................40...........52...55........
1909 Pimoroni PiBrella $17.50 3 $9.90
1910 ok123 456 789 $ 454 2 $ 234
1910 ok123 456 789 $ 454 2 $ 234
1910 ok123 456 789 $ 454 2 $ 234
'''
ski = slice(0, 6)
line_items = invoice.split('\n')[2:]
for item in line_items:
print(item[ski])
/usr/local/bin/python3.7 /Urs/shijianzhong/study/Fluent_Python/第⼆章/t2-4.py
1909
1910
1910
1910
Process finished with exit code 0
⼀个简单的slice的使⽤,平时⼀般我很少⽤。
切⽚可以增删改查,该的话,务必给⼀个可迭代对象。
Out[132]: [1, 2, 1, 2, 3, 4, 4, 5]
In [133]: l = [1,2,3,4,5]
In [134]: l = [0,1,2,3,4,5]
In [135]: l[2:4] = 'hello'
In [136]: l
Out[136]: [0, 1, 'h', 'e', 'l', 'l', 'o', 4, 5]
In [137]: del l[5:]
In [138]: l
Out[138]: [0, 1, 'h', 'e', 'l']
In [139]: l[2:4]=''
In [140]:
In [140]: l
Out[140]: [0, 1, 'l']
上⾯就通过了简单的字符串切⽚赋值操作,很⽅便,由于字符串属于可迭代对象,可以在需要删除的部分直接赋值''空字符串既可。
2.5 对序号使⽤+和*
+和*都遵循这个规则,不修改原来的操作对象,⽽是构建⼀个全新的序列。
In [147]: l + (1,2,3)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in
----> 1 l + (1,2,3)
TypeError: can only concatenate list (not "tuple") to list
In [148]: l + [1,2,3]
Out[148]: [0, 1, 'l', 1, 2, 3]
In [149]: l * 3
Out[149]: [0, 1, 'l', 0, 1, 'l', 0, 1, 'l']
In [150]: l
Out[150]: [0, 1, 'l']
只能跟同类型的相加。
In [151]: l = [[1,2,3]]
In [152]: l1 = l * 3
In [153]: l1
Out[153]: [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
In [154]: l1[0][0]= 'a'
In [155]: l1
Out[155]: [['a', 2, 3], ['a', 2, 3], ['a', 2, 3]]
In [156]:
乘号要注意,⾥⾯的元素都将指向同⼀个变量。
可以⽤列表⽣成式。
In [172]: l = [[1,2,3] for i in range(3)]
In [173]: l
Out[173]: [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
In [174]: l[0][0] = 'a'
In [175]: l
Out[175]: [['a', 2, 3], [1, 2, 3], [1, 2, 3]]
2.6⼀个+=的谜题
In [177]: t = (1,2,[30,40])
In [178]: t[2] += [50,60]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in
----> 1 t[2] += [50,60]
TypeError: 'tuple' object does not support item assignment
In [179]: t
Out[179]: (1, 2, [30, 40, 50, 60])
对⼀个元祖内元素,是列表进⾏了+=操作。有意思的是,由于元祖内的元素不能修改,所以报错了
但由于该元素是可变的,所以修改尽然⼜成功了,有意思。
作者得到是三个教训:
1、不要把可变对象放在元祖⾥⾯。
2、增量赋值不是⼀个原⼦操作。它虽然跑出了异常,但还是完成了操作。
3、我就不说了,他说查看那字节码很简单。。
2.8⽤bict来管理已排序的序列。
bict对于⼤型的已经排好序的元祖或者列表查找索引⾮常快,底层都⽤了2分查找的⽅法。import bict
import sys
import random
HAYSTACK = [1, 3, 8, 13, 14, 15, 19, 21, 22, 24, 24, 25, 27, 28, 29]
NEEDLES = [0, 1, 6, 9, 15, 21, 23, 25, 27, 28, 29, 30]
ROW_FMT = '{0:2d} @ {1:2d} {2}{0:<2d}' # 利⽤了.foramt的格式化对齐<2左对齐
def demo(bict_fn):
for needle in reverd(NEEDLES):
position = bict_fn(HAYSTACK, needle)
offt = position * ' |' # 通过索引划线条
print(ROW_FMT.format(needle, position, offt))
if __name__ == '__main__':
if sys.argv[-1] == 'left':
bict_fn = bict.bict_left # 索引在相同数的前⾯,就是左边
el:
bict_fn = bict.bict # 索引在相同数的右边,就是后⾯
print('Demo:', bict_fn.__name__)
print('haystack ->', ' '.join('%2d' % n for n in HAYSTACK))
demo(bict_fn)
shijianzhongdeMacBook-Pro:第⼆章 shijianzhong$ python3 t2-8.py
Demo: bict_right
haystack -> 1 3 8 13 14 15 19 21 22 24 24 25 27 28 29
30 @ 15 | | | | | | | | | | | | | | |30
29 @ 15 | | | | | | | | | | | | | | |29
28 @ 14 | | | | | | | | | | | | | |28
27 @ 13 | | | | | | | | | | | | |27
25 @ 12 | | | | | | | | | | | |25
23 @ 9 | | | | | | | | |23
21 @ 8 | | | | | | | |21
15 @ 6 | | | | | |15
9 @ 3 | | |9
6 @ 2 | |6
1 @ 1 |1
0 @ 0 0
shijianzhongdeMacBook-Pro:第⼆章 shijianzhong$ python3 t2-8.py left
Demo: bict_left
haystack -> 1 3 8 13 14 15 19 21 22 24 24 25 27 28 29
30 @ 15 | | | | | | | | | | | | | | |30
29 @ 14 | | | | | | | | | | | | | |29
28 @ 13 | | | | | | | | | | | | |28
27 @ 12 | | | | | | | | | | | |27
25 @ 11 | | | | | | | | | | |25
23 @ 9 | | | | | | | | |23
21 @ 7 | | | | | | |21
15 @ 5 | | | | |15
9 @ 3 | | |9
6 @ 2 | |6
1 @ 0 1
0 @ 0 0
作者写的很漂亮的测试代码,逻辑清楚,格式化输出完整,⼤神就是⼤神。膜拜。
从1,15,21可以看出他们的索引其实是不⼀样的。
import bict
def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
i = bict.bict(breakpoints, score)
return grades[i]
print([grade(score) for score in [50, 73, 80, 63, 97, 93, 98, 67, 68, 41]])
/usr/local/bin/python3.7 /Urs/shijianzhong/study/Fluent_Python/第⼆章/t2-8-1.py
['F', 'C', 'B', 'D', 'A', 'A', 'A', 'D', 'D', 'F']
Process finished with exit code 0
这是⼀个通过索引,获取分数等级的代码,我就奇怪,这个bict⽤在⼤量数据的时候⽐较好,为什么书上的实例都是⼩数据。import bict