Python复杂表达式的创建
python 赋值
a = 1
b = a
1 0 LOAD_CONST 0 (1)
2 STORE_NAME 0 (a)
2 4 LOAD_NAME 0 (a)
6 STORE_NAME 1 (b)
8 LOAD_CONST 1 (None)
10 RETURN_VALUE
None
- LOAD_CONST:从const数组中加载一个常量,常量的位置在数组下标为0的位置,该常量值为1。
- STORE_NAME:从names数组中加载一个常量,常量的位置在数组下标为0的位置,该常量值为a。弹出运行时栈顶部,即1,将a,1作为key,value存储在f_locals数组中。
LOAD_NAME:加载变量
- 先从f_locals,中查找变量,找到变量着将变量压入运行时栈。
- 如果在f_locals中未找到变量,则在f_globals中查找变量,将找到的变量压入运行时栈。
- 如果仍未找到,则在f_builtin中寻找变量,将找到的变量压入运行时栈。
- STORE_NAME:从names数组中加载一个常量,常量的位置在数组下标为1的位置,该常量值为b。弹出运行时栈顶部,即1,将b,1作为key,value存储在f_locals数组中。
注意到1没有被复制,只是引用计数加一。
>>> a = 1 >>> b = a >>> id(a) 1534615028160 >>> id(b) 1534615028160 >>>
python 数值运算
a = 1
b = 2
c = a + b
d = a - b
e = a * b
f = a / b
1 0 LOAD_CONST 0 (1)
2 STORE_NAME 0 (a)
2 4 LOAD_CONST 1 (2)
6 STORE_NAME 1 (b)
3 8 LOAD_NAME 0 (a)
10 LOAD_NAME 1 (b)
12 BINARY_ADD
14 STORE_NAME 2 (c)
4 16 LOAD_NAME 0 (a)
18 LOAD_NAME 1 (b)
20 BINARY_SUBTRACT
22 STORE_NAME 3 (d)
5 24 LOAD_NAME 0 (a)
26 LOAD_NAME 1 (b)
28 BINARY_MULTIPLY
30 STORE_NAME 4 (e)
6 32 LOAD_NAME 0 (a)
34 LOAD_NAME 1 (b)
36 BINARY_TRUE_DIVIDE
38 STORE_NAME 5 (f)
40 LOAD_CONST 2 (None)
42 RETURN_VALUE
None
BINARY_ADD:该指令码将运行时栈的顶部弹出赋值给right,再将顶部值赋与left,然后判断right和left类型,选择执行unicode_concatenate或PyNumber_Add。将结果设置为栈顶,TOP()未弹出的内容被覆盖了。
case TARGET(BINARY_ADD): { PyObject *right = POP(); PyObject *left = TOP(); PyObject *sum; /* NOTE(vstinner): Please don't try to micro-optimize int+int on CPython using bytecode, it is simply worthless. See http://bugs.python.org/issue21955 and http://bugs.python.org/issue10044 for the discussion. In short, no patch shown any impact on a realistic benchmark, only a minor speedup on microbenchmarks. */ if (PyUnicode_CheckExact(left) && PyUnicode_CheckExact(right)) { sum = unicode_concatenate(tstate, left, right, f, next_instr); /* unicode_concatenate consumed the ref to left */ } else { sum = PyNumber_Add(left, right); Py_DECREF(left); } Py_DECREF(right); SET_TOP(sum); if (sum == NULL) goto error; DISPATCH(); }
BINARY_SUBTRACT:代码逻辑同BINARY_ADD,调用
PyNumber_Subtract
case TARGET(BINARY_SUBTRACT): { PyObject *right = POP(); PyObject *left = TOP(); PyObject *diff = PyNumber_Subtract(left, right); Py_DECREF(right); Py_DECREF(left); SET_TOP(diff); if (diff == NULL) goto error; DISPATCH(); }
BINARY_MULTIPLY:代码逻辑同BINARY_ADD,调用
PyNumber_Multiply
case TARGET(BINARY_MULTIPLY): { PyObject *right = POP(); PyObject *left = TOP(); PyObject *res = PyNumber_Multiply(left, right); Py_DECREF(left); Py_DECREF(right); SET_TOP(res); if (res == NULL) goto error; DISPATCH(); }
BINARY_TRUE_DIVIDE:代码逻辑同BINARY_ADD,调用
PyNumber_TrueDivide
case TARGET(BINARY_TRUE_DIVIDE): { PyObject *divisor = POP(); PyObject *dividend = TOP(); PyObject *quotient = PyNumber_TrueDivide(dividend, divisor); Py_DECREF(dividend); Py_DECREF(divisor); SET_TOP(quotient); if (quotient == NULL) goto error; DISPATCH(); }
函数调用
a = 1
print(a)
1 0 LOAD_CONST 0 (1)
2 STORE_NAME 0 (a)
2 4 LOAD_NAME 1 (print)
6 LOAD_NAME 0 (a)
8 CALL_FUNCTION 1
10 POP_TOP
12 LOAD_CONST 1 (None)
14 RETURN_VALUE
None
CALL_FUNCTION:CALL_FUNCTION会调用一个可调用对象并传入位置参数。 指令码参数指明函数位置参数的数量。 栈顶包含位置参数,其中最右边的参数在最顶端。 在参数之下是一个待调用的可调用对象。 CALL_FUNCTION 会从栈中弹出所有参数以及可调用对象,附带这些参数调用该可调用对象,并将可调用对象所返回的返回值推入栈顶。
case TARGET(CALL_FUNCTION): { PREDICTED(CALL_FUNCTION); PyObject **sp, *res; sp = stack_pointer; res = call_function(tstate, &trace_info, &sp, oparg, NULL); stack_pointer = sp; PUSH(res); if (res == NULL) { goto error; } CHECK_EVAL_BREAKER(); DISPATCH(); }
16 LOAD_NAME 3 (print) 18 LOAD_NAME 0 (add) 20 LOAD_NAME 1 (num1) 22 LOAD_NAME 2 (num2) 24 CALL_FUNCTION 2 26 CALL_FUNCTION 1
- 在这段指令码中的操作
CALL_FUNCTION 2
,表示从栈中弹出两个参数,即num1与num2被弹出。num1,num2弹出后,还会再弹出一个值,这个值就是函数add,此时在上述指令码所表示的栈中只有print还在其中,在add函数完成后,add函数的结果将会被推入栈中,然后再执行CALL_FUNCTION 1
,add函数的返回值被弹出,然后弹出print函数,执行print函数。 - 这段代码就可以反汇编为
print(add(num1, num2))
- 在这段指令码中的操作
Comments | NOTHING