Skip to main content

Objects/genobject.c

cpython 3.14 @ ab2d84fe1023/Objects/genobject.c

Objects/genobject.c defines PyGenObject, PyCoroObject, and PyAsyncGenObject. All three share the same C struct layout and most of the same machinery; they differ in which opcodes create them, which send/throw methods they expose, and how close() behaves.

Map

LinesSymbolRole
1-150PyGenObject struct, gen_new_with_qualnameObject layout and construction
151-400gen_send_ex2, gen_sendResume the frame and handle the result
401-580gen_throw, gen_closeException injection and close protocol
581-750_PyGen_yf, gen_yfyield from delegation target
751-980PyAsyncGenObject, aclose, athrowAsync generator extras

Reading

gen_send_ex2

gen_send_ex2 is the common resumption path for all three types. It checks that the frame is not already running (prevents re-entry), restores the frame, calls _PyEval_EvalFrameDefault, and translates the result:

  • StopIteration raised: return NULL with no current exception (signals exhaustion)
  • Normal value: the value is whatever YIELD_VALUE put on the stack
  • Any other exception: propagate
// CPython: Objects/genobject.c:190 gen_send_ex2
static PySendResult
gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
int exc, int closing)
{
...
if (gen->gi_frame_state == FRAME_COMPLETED) {
...
*presult = NULL;
return PYGEN_ERROR;
}
...
result = _PyEval_EvalFrameDefault(tstate, frame, exc);
...
}

yield from delegation

_PyGen_yf(gen) returns the object being yield from'd by the generator (if any), by peeking at the value on the suspended frame's stack. SEND and THROW opcodes use this to forward sends and exceptions through chains of generators.

gen_close

gen_close calls gen_throw(GeneratorExit). If the generator handles GeneratorExit and yields again, close() raises RuntimeError. If it returns or re-raises GeneratorExit, close() returns None.

PyAsyncGenObject

Async generators have an additional ag_running_async flag to detect await inside the generator body, and an aclose() method that returns an aclose awaitable.

gopy notes

vm/eval_gen.go implements gen_send_ex2-equivalent logic. Generator frames are stored in objects/function.go. yield from delegation is handled by the SEND opcode in vm/eval_simple.go. Async generator support (PyAsyncGenObject) is partially implemented.