zoukankan      html  css  js  c++  java
  • Python_Tips[2] -> 函数延后估值及字节码分析

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


    在一个循环中定义了函数 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. 闭包函数

  • 相关阅读:
    c++的输入流基础知识
    用英文加优先级来解读C的声明
    django 用imagefiled访问图片
    关于Django中的表单验证
    c#语言的一些复习
    IIS发布的网站用localhost可以访问,改成IP就无法访问的解决方案 .
    首次关于IIS配置遇到的一些问题
    常见dos操作
    vs2012中对于entity framework的使用
    几个知识点
  • 原文地址:https://www.cnblogs.com/stacklike/p/8227584.html
Copyright © 2011-2022 走看看