HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p>Теги: null, python, yield, генераторы в python, execution frame, next(gen_object), pyeval_evalframe, f_stacktop</p>
1 <p>Теги: null, python, yield, генераторы в python, execution frame, next(gen_object), pyeval_evalframe, f_stacktop</p>
2 <p>Все мы знаем и любим генераторы в Python. По сути, генератор - это итератор, который можно использовать в цикле, как обычно. Но генератор дополнительно содержит внутри ключевое слово<strong>yield</strong>.</p>
2 <p>Все мы знаем и любим генераторы в Python. По сути, генератор - это итератор, который можно использовать в цикле, как обычно. Но генератор дополнительно содержит внутри ключевое слово<strong>yield</strong>.</p>
3 <p>После каждого<strong>yield</strong>генератор временно прекращает исполнение и возвращает управление, при следующем вызове стартуя с того места, где закончил в прошлый раз, при этом сохраняя состояние и значения переменных между вызовами.</p>
3 <p>После каждого<strong>yield</strong>генератор временно прекращает исполнение и возвращает управление, при следующем вызове стартуя с того места, где закончил в прошлый раз, при этом сохраняя состояние и значения переменных между вызовами.</p>
4 <h2>Но, чёрт, как он это делает?</h2>
4 <h2>Но, чёрт, как он это делает?</h2>
5 <p>Объект генератор, помимо всего прочего, содержит в себе указатель на текущий<strong>execution frame</strong>, который в свою очередь содержит стек вызова для данного генератора.</p>
5 <p>Объект генератор, помимо всего прочего, содержит в себе указатель на текущий<strong>execution frame</strong>, который в свою очередь содержит стек вызова для данного генератора.</p>
6 <p>Во время вызова next(gen_object) вызывается PyEval_EvalFrame для текущего<strong>execution frame’а</strong>. Это одна из самых главных функций интерпретатора: внутри она, в том числе, знает про ключевое слово<strong>yield</strong>:</p>
6 <p>Во время вызова next(gen_object) вызывается PyEval_EvalFrame для текущего<strong>execution frame’а</strong>. Это одна из самых главных функций интерпретатора: внутри она, в том числе, знает про ключевое слово<strong>yield</strong>:</p>
7 TARGET(YIELD_VALUE) { retval = POP(); f-&gt;f_stacktop = stack_pointer; why = WHY_YIELD; goto fast_yield; }<p>В данном случае возвращается значение, а текущий фрейм сохраняется (<strong>f-&gt;f_stacktop = stack_pointer</strong>), так что после следующего<strong>next</strong>’а можно продолжить там, где остановились, ведь PyEval_EvalFrame будет вызван на том же фрейме, что и раньше, с тем же стеком и состоянием. В обычных функциях<strong>f_stacktop</strong>приравнивается к<strong>NULL</strong>.</p>
7 TARGET(YIELD_VALUE) { retval = POP(); f-&gt;f_stacktop = stack_pointer; why = WHY_YIELD; goto fast_yield; }<p>В данном случае возвращается значение, а текущий фрейм сохраняется (<strong>f-&gt;f_stacktop = stack_pointer</strong>), так что после следующего<strong>next</strong>’а можно продолжить там, где остановились, ведь PyEval_EvalFrame будет вызван на том же фрейме, что и раньше, с тем же стеком и состоянием. В обычных функциях<strong>f_stacktop</strong>приравнивается к<strong>NULL</strong>.</p>
8 <p><em>Есть вопрос? Напишите в комментариях!</em></p>
8 <p><em>Есть вопрос? Напишите в комментариях!</em></p>
9  
9