[英]How to find implementation of for - control flow construct in Python
Have searched SO for the same, and seen the github repository of CPython too;已经搜索了相同的SO,并且也看到了CPython的github存储库; but of no avail.
但无济于事。 It seems that source code implementation of any control flow construct is not visible, but it is not clear why?
似乎看不到任何控制流构造的源代码实现,但不清楚为什么?
In particular need get source code for 'for - control flow construct' in CPython.特别需要在 CPython 中获取“for - 控制流构造”的源代码。
In face of no knowledge, all I could do is to use dis module's dis() on a small code, leading to FOR_ITER opcode, which is not understandable by me.在不知情的情况下,我所能做的就是在一小段代码上使用dis模块的dis(),导致FOR_ITER操作码,我无法理解。
Nor does this opcode lead me into understanding the nested for-loop construct's workings, the reason why I wanted to look into implementation of the same in source code.这个操作码也没有让我了解嵌套的 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
The implementation was added in this commit ;在此提交中添加了实现; here's the part about
FOR_ITER
:这是关于
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;
Ignoring the refcounting, a for x in y:
loop is equivalent to the following Python code:忽略引用计数,一个
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
Considering the subject on current CPython code base (3.8.5):考虑当前 CPython 代码库 (3.8.5) 的主题:
You can see in your disassembly that every FOR_ITER
is preceded by a GET_ITER
.您可以在反汇编中看到,每个
FOR_ITER
前面都有一个GET_ITER
。
GET_ITER source code (check the numbered comments): 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
actually passes to PyObject_GetIter
the object iterable
which is traversed by for
loop. GET_ITER
实际上将for
循环遍历的对象iterable
传递给PyObject_GetIter
。
The code:编码:
iterable
points to top of stack of python objects ;iterable
指向python 对象堆栈的顶部;iter
points to the iterator returned by PyObject_GetIter call;iter
指向PyObject_GetIter调用返回的迭代器;iterable
;iterable
的引用计数;iter
is now on top of stack.iter
现在位于堆栈顶部。 PyObject_GetIter
checks if the iterable is an iterator (ie something that consumes iterables) and if so returns it. PyObject_GetIter
检查迭代器是否是迭代器(即消耗迭代器的东西),如果是则返回它。 If it's not, then checks if it's a sequence.如果不是,则检查它是否是一个序列。 If it is a sequence, then it's converted to an iterator.
如果是序列,则将其转换为迭代器。 That iterator is the returned value.
该迭代器是返回值。
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();
}
Parts of interest:感兴趣的部分:
next (ie tp_iternext)
method call;next (ie tp_iternext)
方法调用的结果;NULL
.NULL
则将结果压入堆栈。 One thing you should be asking: this only covers a single iteration of the loop.您应该问一件事:这仅涵盖循环的一次迭代。 Where is the code that makes the iterator traverse all the items ?
使迭代器遍历所有项目的代码在哪里?
It's the JUMP_ABSOLUTE
opcode that makes the iterator run again, this time on the next element.是
JUMP_ABSOLUTE
操作码使迭代器再次运行,这次是在下一个元素上。 You can see in your original listing that each JUMP_ABSOLUTE
is called with the line number of the corresponding FOR_ITER
opcode, making the iteration possible.您可以在原始清单中看到,每个
JUMP_ABSOLUTE
都使用相应的FOR_ITER
操作码的行号进行FOR_ITER
,从而使迭代成为可能。
This answer is a good reference on this subject too. 这个答案也是关于这个主题的一个很好的参考。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.