文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

字节码:分析 Python 执行的终极利器

2024-12-03 03:48

关注

本文转载自微信公众号「Python中文社区」,作者巩庆奎。转载本文请联系Python中文社区公众号。

一、什么是代码对象

Code Object(代码对象)封装了 Python 虚拟机的字节码和虚拟机执行相关信息,可以把字节码称为 Python 虚拟机上的汇编语言。

学代码对象有什么用呢?从其定义可知,字节码是编译后的 Python 代码,学习代码对象有助于我们理解 Python 虚拟机、编译过程、执行过程,更加深刻理解 Python 语言特性和疑难点。在解决一些疑难杂症时,查看代码对象的字节码往往有事半功倍的效果。

二、探索代码对象

Python 程序由代码块组成,代码块可以是模块、函数或类,也可以是脚本文件,还可以是python - c 'string'和exec ('string')、eval ('string')中字符串的内容。

两种方法:

三、一个函数及其代码对象

我们定义一个函数fun(a,b),它完成简单的加法运算。

  1. def fun(a,b): 
  2.     return a+b  

来看它的代码对象属性情况,我们重点关注以 co_ 开头的属性。

  1. for attr in dir(fun.fun.__code__): 
  2.     if attr.startswith('co_'): 
  3.         print("{attr}:\t{attrs}".format( 
  4.             attrs=getattr(attr=attr,fun.fun.__code__, attr))) 

输出为:

  1. co_argcount: 2 
  2. co_cellvars: () 
  3. co_code: b'|\x00|\x01\x17\x00S\x00' 
  4. co_consts: (None,) 
  5. co_filename: G:\pythonCodeStudy\manuscript\0 bytecode\fun.py 
  6. co_firstlineno: 1 
  7. co_flags: 67 
  8. co_freevars: () 
  9. co_kwonlyargcount: 0 
  10. co_lnotab: b'\x00\x01' 
  11. co_name: fun 
  12. co_names: () 
  13. co_nlocals: 2 
  14. co_posonlyargcount: 0 
  15. co_stacksize: 2 
  16. co_varnames: ('a''b'

fun 函数主体的代码对象的属性意义如下:

Python虚拟机是基于栈的机器,每步函数调用产生栈帧(stack frame)。每个栈帧包含计算栈和块栈。所有参数压入计算栈,调用时弹栈,计算后弹出结果,结束本栈帧。

上例中,我们没有详细解释 co_cellvars 和 co_freevars,下面详细解释。

3.1 co_cellvars 和 co_freevars

co_cellvars 和 co_freevars 是一个相对的概念。我们写一个嵌套函数来解释这两个概念:函数 outer 中,定义了一个变量 e,被内部嵌套函数 inner 引用;inner 函数内部使用了变量 e,但是并未在该块内定义之。

  1. def outer(o1, o2='o2'): 
  2.     e = 'enclose' 
  3.  
  4.     def inner(i1, i2='i2'): 
  5.         print(e) 
  6.         return e 
  7.     return inner 
  8. print(outer.__code__.co_cellvars) 
  9. print(outer('i1').__code__.co_freevars) 

结果。

  1. ('e',) 
  2. ('e',) 

故此,我们知道:

这两个是一体两面的变量。

掌握自由变量的概念,是编写带状态函数、装饰器的基础。

四、字节码细节

字节码看起来就像乱码,如上文 fun 函数的字节码:co_code : b '|\ x00 |\ x01 \ x17 \ x00S \ x00 '。

根据上文,字节码由一位操作码和一位参数组成的序列。让我们分析细节。

co_code [0]表示第一个操作码|,这是 ASCII 码 124 表示的字符,在 include/opcode.h 中,可以看到 124 是 LOAD_FAST 操作码,这是对局部变量列表进行的加载操作。其它类似的:比如 LOAD_CONST 就是对字面常量列表操作,LOAD_GLOBAL 是对全局变量操作。

如果操作码不带参数,参数可以省略。这里的第一个操作码的参数是 co_code[1] 为 0x00 。

因此,这个完整的字节码操作是把局部变量列表 co_varnames 的第 0x00 索引内容 a ,压入计算栈栈顶。

字节序列看起来比较费劲,让我们用 dis.dis(fun)来反汇编代码,得到字节码如下。

  1. 2           0 LOAD_FAST                0 (a) 
  2.             2 LOAD_FAST                1 (b) 
  3.             4 BINARY_ADD 
  4.             6 RETURN_VALUE 

这样看起来就很简单了。

Python 编译产生 pyc 文件:Python3 之前是在本地目录产生,之后是在 pycache 目录下。我们打开上例产生的 pyc 文件,使用十六进制查看,能明显发现,编译的字节码就直接在 PYC 文件里。

五、其它代码块代码对象

上例中,我们对函数进行反汇编,使用的是 dis.dis(fun)指令,这里的 fun 是函数。

第二部分说过得到代码对象有两种方法,当我们对其它代码对象进行 compile 时,实际是对该模块进行反编译。如果此时该代码块里有函数,只会产生代码对象,不会产生真正的函数对象。

比如如下语句:print(dis.dis(compile('def fun(a,b): return a+b', '', 'exec'))),输出如下。可见此时的函数只是一个代码对象,作为常量载入,MAKE_FUNCTION 后,赋值给 fun 局部变量。

  1. 1           0 LOAD_CONST               0 (at 0x00A67B18, file 
  2. ", line 1>) 
  3.             2 LOAD_CONST               1 ('fun'
  4.             4 MAKE_FUNCTION            0 
  5.             6 STORE_NAME               0 (fun) 
  6.             8 LOAD_CONST               2 (None) 
  7.            10 RETURN_VALUE 

六、总结

代码对象封装了 Python 虚拟机的字节码和其它编译相关信息,可以把字节码称为 Python 虚拟机上的汇编语言。我们分析了自由变量和 cell 变量,掌握自由变量的概念,这是编写装饰器、带状态函数的基础。字节码由一位操作码和一位参数组成的序列,学习其细节,有助于我们理解 Python 的特性。可在分析变量作用域、闭包时作为强大的工具。

作者:巩庆奎,大奎,对计算机、电子信息工程感兴趣。gongqingkui at 126.com

 

来源:Python中文社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯