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


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

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

 import dis

 def count():
fs = []
for i in range(1,4):
def f():
return i*i
fs.append(f)
return fs def run():
f1, f2, f3 = count()
# When the function called, the value of i is 3
print(f1())
print(f2())
print(f3()) # dis.dis(count)
run()

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

   5           0 BUILD_LIST               0
3 STORE_FAST 0 (fs) 6 6 SETUP_LOOP 54 (to 63)
9 LOAD_GLOBAL 0 (range)
12 LOAD_CONST 1 (1)
15 LOAD_CONST 2 (4)
18 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
21 GET_ITER
>> 22 FOR_ITER 37 (to 62)
25 STORE_DEREF 0 (i) 7 28 LOAD_CLOSURE 0 (i)
31 BUILD_TUPLE 1
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>)
37 LOAD_CONST 4 ('count.<locals>.f')
40 MAKE_CLOSURE 0
43 STORE_FAST 1 (f) 9 46 LOAD_FAST 0 (fs)
49 LOAD_ATTR 1 (append)
52 LOAD_FAST 1 (f)
55 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
58 POP_TOP
59 JUMP_ABSOLUTE 22
>> 62 POP_BLOCK 10 >> 63 LOAD_FAST 0 (fs)
66 RETURN_VALUE

通过字节码可以看到,

第 10 行进入迭代,

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

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

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

相关阅读


1. 闭包函数

Python_Tips[2] -> 函数延后估值及字节码分析的更多相关文章

  1. Java并发编程原理与实战八:产生线程安全性问题原因(javap字节码分析)

    前面我们说到多线程带来的风险,其中一个很重要的就是安全性,因为其重要性因此,放到本章来进行讲解,那么线程安全性问题产生的原因,我们这节将从底层字节码来进行分析. 一.问题引出 先看一段代码 packa ...

  2. 通过字节码分析this关键字以及异常表的重要作用

    在之前的字节码分析中缺少对异常的介绍,这次主要来对字节码异常表相关的东东进行一个学习,下面先来编写一个相关异常的小程序: 接着编译来看用javap -verbose来查看一下它的字节码信息: xion ...

  3. JVM-String比较-字节码分析

    一道String字符串比较问题引发的字节码分析 public class a { public static void main(String[] args)throws Exception{ } p ...

  4. Java字节码分析

    目录 Java字节码分析 查看字节码详细内容 javap 实例分析 Java字节码分析 对于源码的效率,但从源码来看有时无法分析出准确的结果,因为不同的编译器版本可能会将相同的源码编译成不同的字节码, ...

  5. 通过字节码分析java中的switch语句

    在一次做题中遇到了switch的问题,由于对switch执行顺序的不了解,在这里简单的通过字节码的方式理解一下switch执行顺序(题目如下): public class Ag{ static pub ...

  6. Java Eclipse编译后产生的字节码文件,用DOS命令符怎么打开

    在很多初学者刚刚接触eclipse的时候,写完一个代码文件.例如 Demo.java 通过run as a java application生成之后,会产生一个Demo.class. Demo.cla ...

  7. 深挖JDK动态代理(二):JDK动态生成后的字节码分析

    接上一篇文章深挖JDK动态代理(一)我们来分析一下JDK生成动态的代理类究竟是个什么东西 1. 将生成的代理类编程一个class文件,通过以下方法 public static void transCl ...

  8. java中i=i++字节码分析

    原文出处: Ticmy 1 2 int i = 0; i = i++; 结果还是0为什么? 程序的执行顺序是这样的:因为++在后面,所以先使用i,"使用"的含义就是i++这个表达式 ...

  9. Java finally语句到底是在return之前还是之后执行(JVM字节码分析及内部体系结构)?

    之前看了一篇关于"Java finally语句到底是在return之前还是之后执行?"这样的博客,看到兴致处,突然博客里的一个测试用例让我产生了疑惑. 测试用例如下: public ...

随机推荐

  1. 【Matrix Factorization】林轩田机器学习技法

    在NNet这个系列中讲了Matrix Factorization感觉上怪怪的,但是听完第一小节课程就明白了. 林首先介绍了机器学习里面比较困难的一种问题:categorical features 这种 ...

  2. B树、B-树、B+树、B*树 红黑树

    转载自:http://blog.csdn.net/quitepig/article/details/8041308 B树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): ...

  3. ASP.NET Core [2]:Middleware-请求管道的构成(笔记)

    原文链接:http://www.cnblogs.com/RainingNight/p/middleware-in-asp-net-core.html 中间件处理请求主要分为三个阶段:1. 中间件的注册 ...

  4. FluentAPI深入

    1.  HasMaxLenght 设定字段得最大长度: static void Main(string[] args) { using (TestDbContext ctx = new TestDbC ...

  5. linux误删除恢复

    extundelete 大家基本都知道,在linux上误删除了东西后果是很严重的,尤其是在服务器上误删除了东西,对于字符终端,想要实现恢复删除的数据更是难上加难,对于Linux误删除了重要的东西,虽然 ...

  6. Application_Start事件中用Timer做一个循环任务

    protected void Application_Start(object sender, EventArgs e) { System.Timers.Timer timer = new Syste ...

  7. C#后端调用前端的方法

    在我实际开发过程中,刚好遇到c#后端要调用前端js中的方法,所以研究了一下,特分享如下: 前端代码: <%@ Page Language="C#" AutoEventWire ...

  8. Qt编程的一些技巧

    1.Qt程序在运行过程中,调用函数(如lcdNumber->display(num))显示数据到界面上时,并不会马上刷新屏幕显示,而是要等主程序运行到函数a.exec()时,才刷新屏幕,如下 因 ...

  9. XJOI NOIP模拟题1

    第一题 分析: 开始想的是贪心,取每列均值最大一段. 应该是01分数规划,具体看代码 代码: program gold; var a:..]of int64; n,i,m,j,x:longint; f ...

  10. Android开发中Parcelable接口的使用方法

    在网上看到很多Android初入门的童鞋都在问Parcelable接口的使用方法,小编参考了相关Android教程,看到里面介绍的序列化方法主要有两种分别是实现Serializable接口和实现Par ...