[英]How to find implementation of for - control flow construct in Python
已经搜索了相同的SO,并且也看到了CPython的github存储库; 但无济于事。 似乎看不到任何控制流构造的源代码实现,但不清楚为什么?
特别需要在 CPython 中获取“for - 控制流构造”的源代码。
在不知情的情况下,我所能做的就是在一小段代码上使用dis模块的dis(),导致FOR_ITER操作码,我无法理解。
这个操作码也没有让我了解嵌套的 for 循环结构的工作原理,这也是我想研究源代码中相同结构的实现的原因。
>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
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
实际上将for
循环遍历的对象iterable
传递给PyObject_GetIter
。
编码:
iterable
指向python 对象堆栈的顶部;iter
指向PyObject_GetIter调用返回的迭代器;iterable
的引用计数;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();
}
感兴趣的部分:
next (ie tp_iternext)
方法调用的结果;NULL
则将结果压入堆栈。您应该问一件事:这仅涵盖循环的一次迭代。 使迭代器遍历所有项目的代码在哪里?
是JUMP_ABSOLUTE
操作码使迭代器再次运行,这次是在下一个元素上。 您可以在原始清单中看到,每个JUMP_ABSOLUTE
都使用相应的FOR_ITER
操作码的行号进行FOR_ITER
,从而使迭代成为可能。
这个答案也是关于这个主题的一个很好的参考。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.