fluent python reading notes
列表推导式
最常见的一种写法
1 | symboles = 'ABC%^&*#@$' |
但是也可以同时用filter
和map
函数来实现
1 | beyond_ascii = list(filter(lambda x: x > 40, map(ord, symboles))) |
map函数将一个函数作用于list中的每一个值上,filter也是对数组中的每一个值作用一个函数,但是只返回为真的数值,python3中最后返回的是一个filter对象
比如过滤列表中的所有奇数
1 | # 过滤出列表中的所有奇数 |
再比如过滤出1~100中平方根是整数的数字
所谓整数就是能整除1的数字
1 | #过滤出1~100中平方根是整数的数 |
解包
如下是一个比较神奇的栗子,1
2
3
4
5
6# python解包
colors = ['black', 'white']
sizes = ['S', 'M', 'L']
for tshirt in ('%s %s' % (c, s) for c in colors
for s in sizes):
print(tshirt)
这里用一个%
将元组进行了拆包
如何很好地理解列表推导式呢?
你可以将其想象为一个函数,for c in colors for s in sizes
返回值是(c, s)
用一个%
成功地对其进行了拆包转化为字符串形式
下面这幅图应该比较好理解
然后就有了返回值
当然还有这种写法:
1 | a, b, *rst = range(5) |
陷阱
1 | t = (1,2, [30, 40]) |
在一个不可变对象中插入了可变对象!
虽然报错但是t的值确实被修改了
对其进行反汇编或者是反编译:
得到:
1 | 3 0 LOAD_CONST 1 (1) |
作者提出的三个教训:
- 不要把可变对象放在元组里面
- 增量赋值不是一个原子操作
- 查看python的字节码并不难,而且了解代码背后的运行机制很有帮助
然后我们就来研究python的字节码
python字节码
变量
LOAD_FAST一般加载局部变量的值,也就是读取值,用于计算或者函数调用传参等。
STORE_FAST一般用于保存值到局部变量。
比如:
1 | 61 77 LOAD_FAST 0 (n) |
INPLACE_DIVIDE
就是原地除法,先加载n,然后加载p,然后除法,然后保存结果
对应的就是
n = n/p
如何区分函数形参和其他的局部变量?
形参没有初始化,也就是从函数开始到LOAD_FAST该变量的位置,如果没有看到STORE_FAST,那么该变量就是函数形参。
1 | 4 0 LOAD_CONST 1 (0) |
这里arg1
就没有STORE_FAST
所以对应的源代码为:
1 | def test(arg1): |
全局变量
LOAD_GLOBAL用来加载全局变量,包括指定函数名,类名,模块名等全局符号。
1 | 8 6 LOAD_CONST 2 (101) |
对应的python代码:
1 | def test(): |
常用数据类型
BUILD_LIST用于创建一个list结构。
如果是用列表推导式呢?
BUILD_MAP用于创建一个空的dict。STORE_MAP用于初始化dict的内容。
1 | 3 0 LOAD_CONST 1 ('a') |