Python复杂表达式的创建


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))

声明:Hello World|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - Python复杂表达式的创建


我的朋友,理论是灰色的,而生活之树是常青的!