Python 中的代码对象 code object
与 __code__
属性
0. 参考资料
- What is a code object in Python?
(本文大部分借鉴、翻译自这篇文章) - inspect — Inspect live objects
- PyCodeObject与Python程序执行
1. 概念
代码对象 code object
是一段可执行的 Python
代码在 CPython
中的内部表示。
可执行的 Python
代码包括:
- 函数
- 模块
- 类
- 生成器表达式
当你运行一段代码时,它被解析并编译成代码对象,随后被 CPython
虚拟机执行。
代码对象包含一系列直接操作虚拟机内部状态的指令。
这跟你在用 C
语言编程时是类似的,你写出人类可读的文本,然后用编译器转换成二进制形式,二进制代码(C
的机器码或者是 Python
的字节码)被 CPU
(对于 C
语言来说)或者 CPython
虚拟机虚拟的 CPU
直接执行。
代码对象除了包含 指令,还提供了虚拟机运行代码所需要的一些 额外信息。
2. 探索
以下的内容是在 Python 3.7
中实验的,而且主要是针对于函数来讲。至于模块和类虽然也是通过代码对象实现的(实际上,.pyc
文件里面就存放着序列化的模块代码对象),但是代码对象的大多数特性主要和函数相关。
关于版本需要注意两点:
- 在
Python 2
中,函数的代码对象通过函数.func_code
来访问;而Python 3
中,则需要通过函数.__code__
来访问。 Python 3
的代码对象增加了一个新属性co_kwonlyargcount
,对应强制关键字参数keyword-only argument
。
首先在控制台找出属于 函数.__code__
的所有不以双下划线开头的属性,一共有 15
个。
>>> li = [i for i in dir((lambda: 0).__code__) if not i.startswith('__')]
>>> print(li)
['co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
>>> len(li)
15
以下内容来自官方文档:
属性 | 描述 |
---|---|
co_argcount |
number of arguments (not including keyword only arguments, * or ** args) |
co_code |
string of raw compiled bytecode |
co_cellvars |
tuple of names of cell variables (referenced by containing scopes) |
co_consts |
tuple of constants used in the bytecode |
co_filename |
name of file in which this code object was created |
co_firstlineno |
number of first line in Python source code |
co_flags |
bitmap of CO_* flags, read more here |
co_lnotab |
encoded mapping of line numbers to bytecode indices |
co_freevars |
tuple of names of free variables (referenced via a function’s closure) |
co_kwonlyargcount |
number of keyword only arguments (not including ** arg) |
co_name |
name with which this code object was defined |
co_names |
tuple of names of local variables |
co_nlocals |
number of local variables |
co_stacksize |
virtual machine stack space required |
co_varnames |
tuple of names of arguments and local variables |
下面逐个解释:
co_argcount
:函数接收参数的个数,不包括*args
和**kwargs
以及强制关键字参数。
>>> def test(a, b, c, d=1, e=2, *args, f=3, g, h=4, **kwargs):
... print(a, b, c, d, e, f, g, h, args, kwargs)
...
>>> code_obj = test.__code__
>>> code_obj.co_argcount
5
co_code
:二进制格式的字节码bytecode
,以字节串bytes
的形式存储(在Python 2
中以str
类型存储)。它为虚拟机提供一系列的指令。函数从第一条指令开始执行,在碰到RETURN_VALUE
指令的时候停止执行。
其他字节码指令
bytecode instruction
请参阅官方文档:
Python Bytecode Instructions
字节码中每个指令所占字节数是不一样的。
每条指令都有一个操作码 opcode
,它指明了虚拟机需要进行的操作,还有一个可选的参数,这个参数是一个整数。
操作码 opcode
是单字节的整数,所以最多有 256
个不同的操作码,尽管其中很多没有被用到。
每个操作码都有名字,在 dis
模块的 dis
函数的输出中可以见到,同时它们在 opcode