https://baike.baidu.com/item/Python/407313?fr=aladdin
https://www.jianshu.com/p/f540e540f940 这里介绍了opcod.h
python在执行时,首先会将.py文件中的源代码编译成Python的byte code(字节码),然后用python virtual machine来执行这些编译好的byte code。这种机制跟Java,.Net是一致的,但是python的虚拟机抽象层次更高
- byte code
字节码是一种包含执行程序,由一序列op代码/数据对组成的二进制文件,是一种中间码,它比机器码更抽象
- opcode
opcode(operating code)就是机内码、操作码,也就是指令序列号,用来告诉CPU需要执行哪一条指令
- 指令码
指令码(Instruction Code) /机器码(Machine Code),计算机指令代码,机器语言,用来表示指令集中的指令的代码
- dis
https://www.jianshu.com/p/f45e443cdfd7 解释了opcode与优化
dis是python提供的对操作码进行分析的内置模块
def func():
a = 10
b = 20
c = a + b
return c
dis.dis(func)
###输出结果
2 0 LOAD_CONST 1 (10)
3 STORE_FAST 0 (a)
3 6 LOAD_CONST 2 (20)
9 STORE_FAST 1 (b)
4 12 LOAD_FAST 0 (a)
15 LOAD_FAST 1 (b)
18 BINARY_ADD
19 STORE_FAST 2 (c)
5 22 LOAD_FAST 2 (c)
25 RETURN_VALUE
###
这里面的LOAD_CONST STORE_FAST以及BINARY_ADD即是我们opcode,python基于栈语言,这里LOAD_CONST即为压栈操作,而STORE_FAST是将栈顶元素赋给参数指定的变量。
python代码在编译完成后再内存种的对象称为PyCodeObject,用c定义
typedef struct {
PyObject_HEAD
int co_argcount; /* #arguments, except *args */
int co_kwonlyargcount; /* #keyword only arguments */
int co_nlocals; /* #local variables */
int co_stacksize; /* #entries needed for evaluation stack */
int co_flags; /* CO_..., see below */
PyObject *co_code; /* instruction opcodes */
PyObject *co_consts; /* list (constants used) */
PyObject *co_names; /* list of strings (names used) */
PyObject *co_varnames; /* tuple of strings (local variable names) */
PyObject *co_freevars; /* tuple of strings (free variable names) */
PyObject *co_cellvars; /* tuple of strings (cell variable names) */
/* The rest doesn't count for hash or comparisons */
unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */
PyObject *co_filename; /* unicode (where it was loaded from) */
PyObject *co_name; /* unicode (name, for reference) */
int co_firstlineno; /* first source line number */
PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See
Objects/lnotab_notes.txt for details. */
void *co_zombieframe; /* for optimization only (see frameobject.c) */
PyObject *co_weakreflist; /* to support weakrefs to code objects */
} PyCodeObject;
这里的co_consts和co_names分别存放了所有的常量和所有的变量。
LOAD_CONST 0 表示将co_consts中的第0个(下标0)放入栈中。
STORE_FAST 0 表示将栈顶元素赋值给co_names中存放的第0个元素。
co_code中存储了操作码序列,编译好的操作码以二进制的方式进行存储,co_code = [(opcode}[args{0,1}]+的形式,其中opcode占用一个byte,编号90以下的操作码不需要参数,90及以上的操作码需要两个byte的args,下面是func函数编译之后得到的PyCodeObject信息
https://github.com/yukunxie/PythonCodeObjectParser/blob/master/codeparser.py这里提供了pythonObject的查看工具
<item idx="0" name="func" type="codeobject">
<co_consts count="3">
<item idx="0">None</item>
<item idx="1">10</item>
<item idx="2">20</item>
</co_consts>
<co_names count="0"/>
<co_varnames count="3">
<name idx="0">a</name>
<name idx="1">b</name>
<name idx="2">c</name>
</co_varnames>
<co_cellvars count="0"/>
<co_freevars count="0"/>
<co_filename>code.py</co_filename>
<co_ename>func</co_ename>
<co_nlocals>3</co_nlocals>
<co_stacksize>2</co_stacksize>
<co_argcount>0</co_argcount>
<co_code>6401007d00006402007d01007c00007c0100177d02007c020053</co_code>
</item>
python是基于栈操作的,所以频繁的出栈和压栈的操作,效率较低