Python 源码分析之字节码之基本操作

版权声明:本文系原创,转发请注明出处,商业用途联系作者 https://blog.csdn.net/wenxueliu/article/details/80919947

本文基于 Python 3.6.4 编译器生成字节码,你可通过如下代码片段得到
python 源码对应的字节码

#!/usr/bin/env python
# encoding: utf-8

import sys
import dis

filename=sys.argv[1]
f = open(filename, 'rb')
content = f.read()
c = compile(content, filename, "exec")
dis.dis(c)

指令执行

所有的字节码都位于 Python/ceval.c 文件

//元祖的第 i 个元素
#define GETITEM(v, i) PyTuple_GetItem((v), (i))

//调整栈顶指针
#define BASIC_STACKADJ(n) (stack_pointer += n)
#define STACKADJ(n)     { (void)(BASIC_STACKADJ(n), \
                          lltrace && prtrace(TOP(), "stackadj")); \
                          assert(STACK_LEVEL() <= co->co_stacksize); }
//入栈
#define BASIC_PUSH(v)     (*stack_pointer++ = (v))
#define PUSH(v)         { (void)(BASIC_PUSH(v), \
                          lltrace && prtrace(TOP(), "push")); \
                          assert(STACK_LEVEL() <= co->co_stacksize); }
//出栈
#define BASIC_POP()       (*--stack_pointer)
#define POP()           ((void)(lltrace && prtrace(TOP(), "pop")), \
                         BASIC_POP())

//指向下一条指令
#define DISPATCH() \
    { \
        if (!_Py_atomic_load_relaxed(&eval_breaker)) {      \
                    FAST_DISPATCH(); \
        } \
        continue; \
    }

#ifdef LLTRACE
#define FAST_DISPATCH() \
    { \
        if (!lltrace && !_Py_TracingPossible && !PyDTrace_LINE_ENABLED()) { \
            f->f_lasti = INSTR_OFFSET(); \
            NEXTOPARG(); \
            goto *opcode_targets[opcode]; \
        } \
        goto fast_next_opcode; \
    }
#else
#define FAST_DISPATCH() \
    { \
        if (!_Py_TracingPossible && !PyDTrace_LINE_ENABLED()) { \
            f->f_lasti = INSTR_OFFSET(); \
            NEXTOPARG(); \
            goto *opcode_targets[opcode]; \
        } \
        goto fast_next_opcode; \
    }
#endif
#define JUMPBY(x)       (next_instr += (x) / sizeof(_Py_CODEUNIT))
#define JUMPTO(x)       (next_instr = first_instr + (x) / sizeof(_Py_CODEUNIT))
typedef uint16_t _Py_CODEUNIT
#!/usr/bin/env python
# encoding: utf-8

i = 1
s = "Python"
d = {}
l = {}

对应的字节码为

  4           0 LOAD_CONST               0 (1)
              2 STORE_NAME               0 (i)

  5           4 LOAD_CONST               1 ('Python')
              6 STORE_NAME               1 (s)

  6           8 BUILD_MAP                0
             10 STORE_NAME               2 (d)
             12 LOAD_CONST               2 (None)
             14 RETURN_VALUE

注:第一列为源代码行号,第二列为指令索引, 第三列为指令,第四列为指令的参数,第五列为指令参数对应的值(提示)。

TARGET(LOAD_CONST) {
    # 从常量表中获取索引为 oparg 的元素,其值为 value
    PyObject *value = GETITEM(consts, oparg);
    Py_INCREF(value);
    PUSH(value);
    FAST_DISPATCH();
}
TARGET(STORE_NAME) {
    //从符号表获取第 oparg 个元素作为变量名 name
    PyObject *name = GETITEM(names, oparg);
    //将栈顶元素赋值给 v,并将栈指针减 1
    PyObject *v = POP();
    PyObject *ns = f->f_locals;
    int err;
    if (ns == NULL) {
        PyErr_Format(PyExc_SystemError,
                     "no locals found when storing %R", name);
        Py_DECREF(v);
        goto error;
    }
    if (PyDict_CheckExact(ns))
        //f->f_locals 中设置 name = v
        err = PyDict_SetItem(ns, name, v);
    else
        //ns.name = v
        err = PyObject_SetItem(ns, name, v);
    //引用减一
    Py_DECREF(v);
    if (err != 0)
        goto error;
    DISPATCH();
}
#define PEEK(n)           (stack_pointer[-(n)])
TARGET(BUILD_MAP) {
    Py_ssize_t i;
    //创建一个字典,初始元素个数为 oparg
    PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg);
    if (map == NULL)
        goto error;
    for (i = oparg; i > 0; i--) {
        int err;
        //找到 key
        PyObject *key = PEEK(2*i);
        //找到 value
        PyObject *value = PEEK(2*i - 1);
        //设置 map[key] = value
        err = PyDict_SetItem(map, key, value);
        if (err != 0) {
            Py_DECREF(map);
            goto error;
        }
    }

    while (oparg--) {
        Py_DECREF(POP());
        Py_DECREF(POP());
    }
    PUSH(map);
    DISPATCH();
}
TARGET(BUILD_LIST) {
    //创建一个列表,初始元素个数为 oparg
    PyObject *list =  PyList_New(oparg);
    if (list == NULL)
        goto error;
    //从后往前
    while (--oparg >= 0) {
        //从栈中弹出一个元素
        PyObject *item = POP();
        //设置 list[oparg] = item
        PyList_SET_ITEM(list, oparg, item);
    }
    //list 压栈
    PUSH(list);
    DISPATCH();
}

TARGET(RETURN_VALUE) {
    retval = POP();
    why = WHY_RETURN;
    goto fast_block_end;
}

例 2

#!/usr/bin/env python
# encoding: utf-8

a = 1
b = "Python"
c = a + b
  4           0 LOAD_CONST               0 (1)
              3 STORE_NAME               0 (a)

  5           6 LOAD_CONST               1 ('Python')
              9 STORE_NAME               1 (b)

  6          12 LOAD_NAME                0 (a)
             15 LOAD_NAME                1 (b)
             18 BINARY_ADD
             19 STORE_NAME               2 (c)
             22 LOAD_CONST               2 (None)
             25 RETURN_VALUE
TARGET(LOAD_NAME) {
    //从符号表加载中第 oparg 个元素 name,依次从局部变量表,全局变量表,
    //内置变量表中查找 name 对应找到值,如果找到将该值压栈,如果没有找到抛异常。
    PyObject *name = GETITEM(names, oparg);
    PyObject *locals = f->f_locals;
    PyObject *v;
    //确保局部变量表存在 name
    if (locals == NULL) {
        PyErr_Format(PyExc_SystemError,
                     "no locals when loading %R", name);
        goto error;
    }
    //如果是字典对象,从局部变量表中获取 name 对应的值
    if (PyDict_CheckExact(locals)) {
        v = PyDict_GetItem(locals, name);
        Py_XINCREF(v);
    }
    else {
        v = PyObject_GetItem(locals, name);
        if (v == NULL) {
            if (!PyErr_ExceptionMatches(PyExc_KeyError))
                goto error;
            PyErr_Clear();
        }
    }
    //如果局部变量表不存在该变量,从全局变量中查找
    if (v == NULL) {
        v = PyDict_GetItem(f->f_globals, name);
        Py_XINCREF(v);
        if (v == NULL) {
            # 如果全局变量表中也不存在,从内置变量表中查找
            if (PyDict_CheckExact(f->f_builtins)) {
                v = PyDict_GetItem(f->f_builtins, name);
                if (v == NULL) {
                    format_exc_check_arg(
                                PyExc_NameError,
                                NAME_ERROR_MSG, name);
                    goto error;
                }
                Py_INCREF(v);
            }
            else {
                v = PyObject_GetItem(f->f_builtins, name);
                if (v == NULL) {
                    if (PyErr_ExceptionMatches(PyExc_KeyError))
                        format_exc_check_arg(
                                    PyExc_NameError,
                                    NAME_ERROR_MSG, name);
                    goto error;
                }
            }
        }
    }
    PUSH(v);
    DISPATCH();
}
TARGET(BINARY_ADD) {
    //从栈中弹出右边的变量
    PyObject *right = POP();
    //获取栈顶元素,可见入栈从左往右
    PyObject *left = TOP();
    PyObject *sum;
    if (PyUnicode_CheckExact(left) &&
             PyUnicode_CheckExact(right)) {
        //字符串连接
        sum = unicode_concatenate(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();
}
#!/usr/bin/env python
# encoding: utf-8
c = { "1" : "a", "2": "b" }
c = [1, 2, 3]
  4           0 BUILD_MAP                2
              3 LOAD_CONST               0 ('a')
              6 LOAD_CONST               1 ('1')
              9 STORE_MAP
             10 LOAD_CONST               2 ('b')
             13 LOAD_CONST               3 ('2')
             16 STORE_MAP
             17 STORE_NAME               0 (c)

  5          20 LOAD_CONST               4 (1)
             23 LOAD_CONST               5 (2)
             26 LOAD_CONST               6 (3)
             29 BUILD_LIST               3
             32 STORE_NAME               0 (c)
             35 LOAD_CONST               7 (None)
             38 RETURN_VALUE

可见 map 是加载一个元素,写入 map,再加载一个元素,再写入,依次类推
而 list 一次将所有元素写入栈,然后写入 list

哈哈,这里 list 会不会有栈溢出攻击呢? 我试了下 500 元素构造 list
也是压栈 500 次,之后再加入 list

函数调用

#!/usr/bin/env python
# encoding: utf-8

a = 2
print(a)
  4           0 LOAD_CONST               0 (2)
              2 STORE_NAME               0 (a)

  5           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
PREDICTED(CALL_FUNCTION);
TARGET(CALL_FUNCTION) {
    PyObject **sp, *res;
    PCALL(PCALL_ALL);
    sp = stack_pointer;
    res = call_function(&sp, oparg, NULL);
    stack_pointer = sp;
    PUSH(res);
    if (res == NULL) {
        goto error;
    }
    DISPATCH();
}
#define Py_TYPE(ob)             (((PyObject*)(ob))->ob_type)


static PyObject *
call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
{
    PyObject **pfunc = (*pp_stack) - oparg - 1;
    PyObject *func = *pfunc;
    PyObject *x, *w;
    Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
    Py_ssize_t nargs = oparg - nkwargs;
    PyObject **stack;

    /* Always dispatch PyCFunction first, because these are
       presumed to be the most frequent callable object.
    */
    if (PyCFunction_Check(func)) {
        PyThreadState *tstate = PyThreadState_GET();

        PCALL(PCALL_CFUNCTION);

        stack = (*pp_stack) - nargs - nkwargs;
        C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
    }
    else {
        if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
            /* optimize access to bound methods */
            PyObject *self = PyMethod_GET_SELF(func);
            PCALL(PCALL_METHOD);
            PCALL(PCALL_BOUND_METHOD);
            Py_INCREF(self);
            func = PyMethod_GET_FUNCTION(func);
            Py_INCREF(func);
            Py_SETREF(*pfunc, self);
            nargs++;
        }
        else {
            Py_INCREF(func);
        }

        stack = (*pp_stack) - nargs - nkwargs;

        if (PyFunction_Check(func)) {
            x = fast_function(func, stack, nargs, kwnames);
        }
        else {
            x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);
        }

        Py_DECREF(func);
    }

    assert((x != NULL) ^ (PyErr_Occurred() != NULL));

    /* Clear the stack of the function object.  Also removes
       the arguments in case they weren't consumed already
       (fast_function() and err_args() leave them on the stack).
     */
    while ((*pp_stack) > pfunc) {
        w = EXT_POP(*pp_stack);
        Py_DECREF(w);
        PCALL(PCALL_POP);
    }

    return x;
}

if 语句

#!/usr/bin/env python
# encoding: utf-8

a = 2
if a > 1:
    a = 0

编译之后

  4           0 LOAD_CONST               0 (2)
              2 STORE_NAME               0 (a)

  5           4 LOAD_NAME                0 (a)
              6 LOAD_CONST               1 (1)
              8 COMPARE_OP               4 (>)
             10 POP_JUMP_IF_FALSE       16

  6          12 LOAD_CONST               2 (0)
             14 STORE_NAME               0 (a)
        >>   16 LOAD_CONST               3 (None)
             18 RETURN_VALUE
static PyObject * cmp_outcome(int op, PyObject *v, PyObject *w)
{
    int res = 0;
    switch (op) {
    //...
    default:
        return PyObject_RichCompare(v, w, op);
    }
    v = res ? Py_True : Py_False;
    Py_INCREF(v);
    return v;
}

PyObject *
PyObject_RichCompare(PyObject *v, PyObject *w, int op)
{
    PyObject *res;

    assert(Py_LT <= op && op <= Py_GE);
    if (v == NULL || w == NULL) {
        if (!PyErr_Occurred())
            PyErr_BadInternalCall();
        return NULL;
    }
    if (Py_EnterRecursiveCall(" in comparison"))
        return NULL;
    res = do_richcompare(v, w, op);
    Py_LeaveRecursiveCall();
    return res;
}

//由下可知实际调用的是对象类型的  ob_type->tp_richcompare
static PyObject *
do_richcompare(PyObject *v, PyObject *w, int op)
{
    richcmpfunc f;
    PyObject *res;
    int checked_reverse_op = 0;

    if (v->ob_type != w->ob_type &&
        PyType_IsSubtype(w->ob_type, v->ob_type) &&
        (f = w->ob_type->tp_richcompare) != NULL) {
        checked_reverse_op = 1;
        res = (*f)(w, v, _Py_SwappedOp[op]);
        if (res != Py_NotImplemented)
            return res;
        Py_DECREF(res);
    }
    if ((f = v->ob_type->tp_richcompare) != NULL) {
        res = (*f)(v, w, op);
        if (res != Py_NotImplemented)
            return res;
        Py_DECREF(res);
    }
    if (!checked_reverse_op && (f = w->ob_type->tp_richcompare) != NULL) {
        res = (*f)(w, v, _Py_SwappedOp[op]);
        if (res != Py_NotImplemented)
            return res;
        Py_DECREF(res);
    }
    /* If neither object implements it, provide a sensible default
       for == and !=, but raise an exception for ordering. */
    switch (op) {
    case Py_EQ:
        res = (v == w) ? Py_True : Py_False;
        break;
    case Py_NE:
        res = (v != w) ? Py_True : Py_False;
        break;
    default:
        PyErr_Format(PyExc_TypeError,
                     "'%s' not supported between instances of '%.100s' and '%.100s'",
                     opstrings[op],
                     v->ob_type->tp_name,
                     w->ob_type->tp_name);
        return NULL;
    }
    Py_INCREF(res);
    return res;
}

TARGET(COMPARE_OP) {
    //弹出右值
    PyObject *right = POP();
    //取左值
    PyObject *left = TOP();
    //
    PyObject *res = cmp_outcome(oparg, left, right);
    Py_DECREF(left);
    Py_DECREF(right);
    //结果写入栈顶
    SET_TOP(res);
    if (res == NULL)
        goto error;
    //没有找到 PRED_XXXX 相关代码,但从 C 语言的经验来看应该是分支预测相关,
    //当然这与我们掌握字节码本身关系也不是特别大,暂且跳过。
    PREDICT(POP_JUMP_IF_FALSE);
    PREDICT(POP_JUMP_IF_TRUE);
    DISPATCH();
}

#if defined(DYNAMIC_EXECUTION_PROFILE) || USE_COMPUTED_GOTOS
#define PREDICT(op)             if (0) goto PRED_##op
#else
#define PREDICT(op) \
    do{ \
        _Py_CODEUNIT word = *next_instr; \
        opcode = _Py_OPCODE(word); \
        if (opcode == op){ \
            oparg = _Py_OPARG(word); \
            next_instr++; \
            goto PRED_##op; \
        } \
    } while(0)
#endif
#define PREDICTED(op)           PRED_##op:
PREDICTED(POP_JUMP_IF_FALSE);
TARGET(POP_JUMP_IF_FALSE) {
    PyObject *cond = POP();
    int err;
    //如果为 True,继续执行
    if (cond == Py_True) {
        Py_DECREF(cond);
        FAST_DISPATCH();
    }
    //如果为 False,跳转到参数 oparg 的位置
    if (cond == Py_False) {
        Py_DECREF(cond);
        JUMPTO(oparg);
        FAST_DISPATCH();
    }
    //如果不是 bool 类型,大于 0,设置 err = 0
    //等于 0,跳转到参数 oparg 位置,小于 0,报错
    err = PyObject_IsTrue(cond);
    Py_DECREF(cond);
    if (err > 0)
        err = 0;
    else if (err == 0)
        JUMPTO(oparg);
    else
        goto error;
    DISPATCH();
}

PREDICTED(POP_JUMP_IF_TRUE);
TARGET(POP_JUMP_IF_TRUE) {
    PyObject *cond = POP();
    int err;
    if (cond == Py_False) {
        Py_DECREF(cond);
        FAST_DISPATCH();
    }
    if (cond == Py_True) {
        Py_DECREF(cond);
        JUMPTO(oparg);
        FAST_DISPATCH();
    }
    err = PyObject_IsTrue(cond);
    Py_DECREF(cond);
    if (err > 0) {
        err = 0;
        JUMPTO(oparg);
    }
    else if (err == 0)
        ;
    else
        goto error;
    DISPATCH();
}

for 语句

#!/usr/bin/env python
# encoding: utf-8

a = [1, 2, 3]
for e in a:
    b = e
  9           0 LOAD_CONST               0 (1)
              2 LOAD_CONST               1 (2)
              4 LOAD_CONST               2 (3)
              6 BUILD_LIST               3
              8 STORE_NAME               0 (a)

 10          10 SETUP_LOOP              16 (to 28)
             12 LOAD_NAME                0 (a)
             14 GET_ITER
             # 8/2 = 4,向前跳 4 条指令,本例到了  POP_BLOCK
        >>   16 FOR_ITER                 8 (to 26)
             18 STORE_NAME               1 (e)

 11          20 LOAD_NAME                1 (e)
             22 STORE_NAME               2 (b)
             24 JUMP_ABSOLUTE           16  //调到 FOR_ITER
        >>   26 POP_BLOCK
        >>   28 LOAD_CONST               3 (None)
             30 RETURN_VALUE
const _Py_CODEUNIT *first_instr;
const _Py_CODEUNIT *next_instr;
first_instr = (_Py_CODEUNIT *) PyBytes_AS_STRING(co->co_code);
#define INSTR_OFFSET()  (sizeof(_Py_CODEUNIT) * (int)(next_instr - first_instr))
TARGET(SETUP_LOOP) {
    PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg,
                       STACK_LEVEL());
    DISPATCH();
}

//Objects/frameobject.c
void
PyFrame_BlockSetup(PyFrameObject *f, int type, int handler, int level)
{
    PyTryBlock *b;
    //哈哈,还有代码块溢出 #define CO_MAXBLOCKS 20
    if (f->f_iblock >= CO_MAXBLOCKS)
        Py_FatalError("XXX block stack overflow");
    //将代码块深度加一
    b = &f->f_blockstack[f->f_iblock++];
    b->b_type = type;
    b->b_level = level;
    b->b_handler = handler;
}

//Include/frameobject.h
typedef struct {
    int b_type;                 /* what kind of block this is */
    int b_handler;              /* where to jump to find handler */
    int b_level;                /* value stack level to pop to */
} PyTryBlock;

typedef struct _frame {
     //....
    int f_lineno;               /* Current line number */
    int f_iblock;               /* index in f_blockstack */
    char f_executing;           /* whether the frame is still executing */
    PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
    PyObject *f_localsplus[1];  /* locals+stack, dynamically sized */
} PyFrameObject;
TARGET(GET_ITER) {
    /* before: [obj]; after [getiter(obj)] */
    //获取栈顶元素
    PyObject *iterable = TOP();
    //获取栈顶元素的迭代器,对于 Python 来说,每个对象的类似都是
    //PyTypeObject,而 PyTypeObject 都有一个成员 tp_iter 表示其迭代器。
    //此处不再详述,参考 Objects/abstract.c
    PyObject *iter = PyObject_GetIter(iterable);
    Py_DECREF(iterable);
    //用迭代器替代原有栈顶元素
    SET_TOP(iter);
    if (iter == NULL)
        goto error;
    PREDICT(FOR_ITER);
    PREDICT(CALL_FUNCTION);
    DISPATCH();
}

PREDICTED(FOR_ITER);
TARGET(FOR_ITER) {
    /* before: [iter]; after: [iter, iter()] *or* [] */
    //由 GET_ITER 得知,当前栈顶为 iter
    PyObject *iter = TOP();
    //获取下一个元素
    PyObject *next = (*iter->ob_type->tp_iternext)(iter);
    if (next != NULL) {
        //压栈
        PUSH(next);
        PREDICT(STORE_FAST);
        PREDICT(UNPACK_SEQUENCE);
        //continue 的作用是继续执行下一条指令
        DISPATCH();
    }
    if (PyErr_Occurred()) {
        if (!PyErr_ExceptionMatches(PyExc_StopIteration))
            goto error;
        else if (tstate->c_tracefunc != NULL)
            call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f);
        PyErr_Clear();
    }
    /* iterator ended normally */
    STACKADJ(-1);
    Py_DECREF(iter);
    JUMPBY(oparg);
    PREDICT(POP_BLOCK);
    DISPATCH();
}
        PREDICTED(JUMP_ABSOLUTE);
        TARGET(JUMP_ABSOLUTE) {
            JUMPTO(oparg);
#if FAST_LOOPS
            /* Enabling this path speeds-up all while and for-loops by bypassing
               the per-loop checks for signals.  By default, this should be turned-off
               because it prevents detection of a control-break in tight loops like
               "while 1: pass".  Compile with this option turned-on when you need
               the speed-up and do not need break checking inside tight loops (ones
               that contain only instructions ending with FAST_DISPATCH).
            */
            FAST_DISPATCH();
#else
            DISPATCH();
#endif
        }

PREDICTED(POP_BLOCK);
TARGET(POP_BLOCK) {
    PyTryBlock *b = PyFrame_BlockPop(f);
    UNWIND_BLOCK(b);
    DISPATCH();
}

PyTryBlock *
PyFrame_BlockPop(PyFrameObject *f)
{
    PyTryBlock *b;
    if (f->f_iblock <= 0)
        Py_FatalError("XXX block stack underflow");
    //将代码块深度减一
    b = &f->f_blockstack[--f->f_iblock];
    return b;
}

因此,整个 for 循环的结构如下

 SETUP_LOOP
 ...
 GET_ITER
 FOR_ITER
 ...
 JUMP_ABSOLUTE
 POP_BLOCK

在创建 for 循环的时候 b = &f->f_blockstack[f->f_iblock++];

for 循环执行完的时候 b = &f->f_blockstack[–f->f_iblock];

最后,

#!/usr/bin/env python
# encoding: utf-8

for i in range(10):
    for i in range(10):
        for i in range(10):
            for i in range(10):
                for i in range(10):
                    for i in range(10):
                        for i in range(10):
                            for i in range(10):
                                for i in range(10):
                                    for i in range(10):
                                        for i in range(10):
                                            for i in range(10):
                                                for i in range(10):
                                                    for i in range(10):
                                                        for i in range(10):
                                                            for i in range(10):
                                                                for i in range(10):
                                                                    for i in range(10):
                                                                        a = 1

这估计是一道非常难的 python 面试题了, 猜猜结果是什么,哈哈,如果换成 21 层 for
循环呢?

while 循环

#!/usr/bin/env python
# encoding: utf-8
i = 0
while i > 10:
    i += 1
    if i > 5:
        continue
    if i == 9:
        break
    b = 1

字节码

  9           0 LOAD_CONST               0 (0)
              2 STORE_NAME               0 (i)

 10           4 SETUP_LOOP              44 (to 50)
        >>    6 LOAD_NAME                0 (i)
              8 LOAD_CONST               1 (10)
             10 COMPARE_OP               0 (<)
             12 POP_JUMP_IF_FALSE       48

 11          14 LOAD_NAME                0 (i)
             16 LOAD_CONST               2 (1)
             18 INPLACE_ADD
             20 STORE_NAME               0 (i)

 12          22 LOAD_NAME                0 (i)
             24 LOAD_CONST               3 (5)
             26 COMPARE_OP               4 (>)
             28 POP_JUMP_IF_FALSE       32

 13          30 JUMP_ABSOLUTE            6    //continue

 14     >>   32 LOAD_NAME                0 (i)
             34 LOAD_CONST               4 (9)
             36 COMPARE_OP               2 (==)
             38 POP_JUMP_IF_FALSE       42

 15          40 BREAK_LOOP

 16     >>   42 LOAD_CONST               2 (1)
             44 STORE_NAME               1 (b)
             46 JUMP_ABSOLUTE            6
        >>   48 POP_BLOCK
        >>   50 LOAD_CONST               5 (None)
             52 RETURN_VALUE
TARGET(BREAK_LOOP) {
    why = WHY_BREAK;
    goto fast_block_end;
}


fast_block_end:
        /* Unwind stacks if a (pseudo) exception occurred */
        while (why != WHY_NOT && f->f_iblock > 0) {
            /* Peek at the current block. */
            PyTryBlock *b = &f->f_blockstack[f->f_iblock - 1];

            /* Now we have to pop the block. */
            f->f_iblock--;

            if (b->b_type == EXCEPT_HANDLER) {
                UNWIND_EXCEPT_HANDLER(b);
                continue;
            }
            UNWIND_BLOCK(b);
            //执行这里
            if (b->b_type == SETUP_LOOP && why == WHY_BREAK) {
                //设置 why
                why = WHY_NOT;
                //调整到 b->b_handler,b->b_handler 实际上就是 SETUP_LOOP 的参数
                JUMPTO(b->b_handler);
                break;
            }

剩下的都是熟悉的指令,熟悉的面孔。

因此,整个 for 循环的结构如下

 SETUP_LOOP
 ...
 COMPARE_OP
 POP_JUMP_IF_FALSE
 ...
 JUMP_ABSOLUTE
 POP_BLOCK

在创建 for 循环的时候 b = &f->f_blockstack[f->f_iblock++];

for 循环执行完的时候 b = &f->f_blockstack[–f->f_iblock];

猜你喜欢

转载自blog.csdn.net/wenxueliu/article/details/80919947