[英]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.