Python_Tips[2] -> 函数延后估值及字节码分析

本文探讨了在Python中定义闭包函数时遇到的变量延后估值问题,并通过字节码分析验证了闭包中变量引用的行为。当在循环中定义多个闭包函数但延迟调用时,所有闭包将引用最后一次循环后的变量值。

函数延后估值及字节码分析


 

在一个循环中定义了函数 f 但是并未对其进行调用,在循环结束后调用,此时i值为3故最终3个函数输出均为9。而非1, 4, 9。

这是由于在定义闭包函数 f 时,传入变量 i,而在循环结束后才调用函数,此时的 i 已为 3,下面使用字节码来查看并论证这一运行顺序。

 1 import dis
 2 
 3 def count():
 4     fs = []
 5     for i in range(1,4):
 6         def f():
 7             return i*i
 8         fs.append(f)
 9     return fs
10 
11 def run():
12     f1, f2, f3 = count()
13     # When the function called, the value of i is 3
14     print(f1())
15     print(f2())
16     print(f3())
17 
18 # dis.dis(count)
19 run()

 

使用 dis对count函数的字节码进行查看,得到解释器运行字节码如下

 1   5           0 BUILD_LIST               0
 2               3 STORE_FAST               0 (fs)
 3 
 4   6           6 SETUP_LOOP              54 (to 63)
 5               9 LOAD_GLOBAL              0 (range)
 6              12 LOAD_CONST               1 (1)
 7              15 LOAD_CONST               2 (4)
 8              18 CALL_FUNCTION            2 (2 positional, 0 keyword pair)
 9              21 GET_ITER
10         >>   22 FOR_ITER                37 (to 62)
11              25 STORE_DEREF              0 (i)
12 
13   7          28 LOAD_CLOSURE             0 (i)
14              31 BUILD_TUPLE              1
15              34 LOAD_CONST               3 (<code object f at 0x0000000000547AE0, file "C:/Users/XXXXX/Documents/Python Note/10_Python_Tips/10.4_Method_Call/Method_Call.py", line 7>)
16              37 LOAD_CONST               4 ('count.<locals>.f')
17              40 MAKE_CLOSURE             0
18              43 STORE_FAST               1 (f)
19 
20   9          46 LOAD_FAST                0 (fs)
21              49 LOAD_ATTR                1 (append)
22              52 LOAD_FAST                1 (f)
23              55 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
24              58 POP_TOP
25              59 JUMP_ABSOLUTE           22
26         >>   62 POP_BLOCK
27 
28  10     >>   63 LOAD_FAST                0 (fs)
29              66 RETURN_VALUE

通过字节码可以看到,

第 10 行进入迭代,

第 11 行中的 STORE_DEREF 会更新变量 i 的值,

第 13 行开始,进入到函数 f 定义的部分,而第 13 行则是关键,这里载入 Enclosure 即闭包上层的局部变量 i,而不是当前 i 的值,随后完成整个闭包函数 f 并返回。

因此,在 3 个函数 f 中,所存储的均为变量 i,所以在调用时结果自然相同。

 

相关阅读


1. 闭包函数

 

转载于:https://www.cnblogs.com/stacklike/p/8227584.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值