Chow以找到Python中的For语言 - Control Flow构建体的实现



已经搜索了相同的搜索,并看到了cpython的github存储库;但无济于事。似乎不可见任何控制流构建体的源代码实现,但尚不清楚为什么?

尤其需要获取cpython中的" for -control Flow构造"的源代码。

面对一无所知,我所能做的就是在小型代码上使用dis模块的dis(),导致for_iter opcode,这是我无法理解的。
此操作码也不会使我理解嵌套的循环结构的工作,这是我想在源代码中研究相同的原因。

>import dis
 def foo():
 for i in range(3):
     for j in range(2):
         print(i,j)
 dis.dis(foo)
 3           0 SETUP_LOOP              44 (to 46)
             2 LOAD_GLOBAL              0 (range)
             4 LOAD_CONST               1 (3)
             6 CALL_FUNCTION            1
             8 GET_ITER
       >>   10 FOR_ITER                32 (to 44)
            12 STORE_FAST               0 (i)
 4          14 SETUP_LOOP              26 (to 42)
            16 LOAD_GLOBAL              0 (range)
            18 LOAD_CONST               2 (2)
            20 CALL_FUNCTION            1
            22 GET_ITER
       >>   24 FOR_ITER                14 (to 40)
            26 STORE_FAST               1 (j)
 5          28 LOAD_GLOBAL              1 (print)
            30 LOAD_FAST                0 (i)
            32 LOAD_FAST                1 (j)
            34 CALL_FUNCTION            2
            36 POP_TOP
            38 JUMP_ABSOLUTE           24
       >>   40 POP_BLOCK
       >>   42 JUMP_ABSOLUTE           10
       >>   44 POP_BLOCK
       >>   46 LOAD_CONST               0 (None)
            48 RETURN_VALUE

在此提交中添加了实现;这是有关FOR_ITER的部分:

        case FOR_ITER:
            /* before: [iter]; after: [iter, iter()] *or* [] */
            v = TOP();
            x = PyObject_CallObject(v, NULL);
            if (x == NULL) {
                if (PyErr_ExceptionMatches(
                    PyExc_StopIteration))
                {
                    PyErr_Clear();
                    x = v = POP();
                    Py_DECREF(v);
                    JUMPBY(oparg);
                    continue;
                }
                break;
            }
            PUSH(x);
            continue;

忽略倒数,for x in y:循环等同于以下Python代码:

# GET_ITER
y_iter = iter(y)
# FOR_ITER
while True:
    try:
        x = next(y_iter)
    except StopIteration:
        break
    # body of for loop
    pass

考虑当前CPYTHON代码基础上的主题(3.8.5):

您可以在拆卸中看到每个FOR_ITER都有GET_ITER

get_iter源代码(检查编号注释):

    case TARGET(GET_ITER): {
        /* before: [obj]; after [getiter(obj)] */
        PyObject *iterable = TOP(); // 1.
        PyObject *iter = PyObject_GetIter(iterable); // 2.
        Py_DECREF(iterable); // 3.
        SET_TOP(iter); // 4.
        if (iter == NULL)
            goto error;
        PREDICT(FOR_ITER);
        PREDICT(CALL_FUNCTION);
        DISPATCH();
    }

GET_ITER实际上传递到PyObject_GetIterfor循环穿越的对象iterable

代码:

  1. iterable点到python对象的堆栈顶部;
  2. 使iter点点到由PyObject_getiter Call返回的迭代器;
  3. 将参考计数减少到iterable;
  4. 迭代器iter现在位于堆栈顶部。

PyObject_GetIter检查峰值是否是迭代器(即消耗迭代的东西),如果是的,则返回它。如果不是,请检查是否是序列。如果是序列,则将其转换为迭代器。迭代器是返回的值。


for_iter代码:

    case TARGET(FOR_ITER): {
        PREDICTED(FOR_ITER);
        /* before: [iter]; after: [iter, iter()] *or* [] */
        PyObject *iter = TOP(); // 1.
        PyObject *next = (*iter->ob_type->tp_iternext)(iter); // 2.
        if (next != NULL) {
            PUSH(next); // 3.
            PREDICT(STORE_FAST);
            PREDICT(UNPACK_SEQUENCE);
            DISPATCH();
        }
        if (_PyErr_Occurred(tstate)) {
            if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) {
                goto error;
            }
            else if (tstate->c_tracefunc != NULL) {
                call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f);
            }
            _PyErr_Clear(tstate);
        }
        /* iterator ended normally */
        STACK_SHRINK(1);
        Py_DECREF(iter);
        JUMPBY(oparg);
        PREDICT(POP_BLOCK);
        DISPATCH();
    }

感兴趣的部分:

  1. 从堆栈顶部获取迭代器;
  2. 获得next (i.e. tp_iternext)方法调用的结果;
  3. 如果不是NULL,则将结果推入堆栈。

您应该问的一件事:这仅涵盖循环的单个迭代。使迭代器穿越所有项目的代码在哪里?

JUMP_ABSOLUTE OpCode,使迭代器再次运行,这次是在下一个元素上。您可以在原始列表中看到每个JUMP_ABSOLUTE都与相应的FOR_ITER OPCODE的行号调用,从而使迭代成为可能。

这个答案也是关于此主题的很好的参考。

最新更新