Skip to main content

Include/cpython/iterobject.h

cpython 3.14 @ ab2d84fe1023/Include/cpython/iterobject.h

This header exposes the two built-in iterator types that CPython creates internally. PySeqIterObject drives iteration over objects that implement sq_item (the sequence protocol). PyCallIterObject drives iteration via a callable plus a sentinel value, as produced by the two-argument form of iter(callable, sentinel). Neither struct is part of the stable ABI; they are exposed here so the interpreter core and a handful of C extension modules can reach inside them without a function call.

Map​

SymbolKindNotes
PySeqIterObjectstructHolds si_seq (the object being iterated) and si_index (next index).
seqiterobjecttypedefAlias for PySeqIterObject.
PySeqIter_Check(op)macroTrue when op is a sequence iterator.
PyCallIterObjectstructHolds it_callable and it_sentinel.
calliterobjecttypedefAlias for PyCallIterObject.
PyCallIter_Check(op)macroTrue when op is a call iterator.

Public constructors (PySeqIter_New, PyCallIter_New) live in Include/abstract.h and Objects/iterobject.c; this header only adds the struct layouts and the fast-check macros.

Reading​

Sequence iterator layout​

typedef struct {
PyObject_HEAD
Py_ssize_t si_index;
PyObject *si_seq; /* set to NULL when iterator is exhausted */
} PySeqIterObject;

si_seq is set to NULL when the iterator is exhausted or the underlying sequence is deleted. Every tp_iternext implementation must check for this before calling sq_item. The si_index field starts at 0 and is incremented after each successful fetch; on IndexError the field is left at its last value and si_seq is cleared.

Call iterator layout​

typedef struct {
PyObject_HEAD
PyObject *it_callable;
PyObject *it_sentinel;
} PyCallIterObject;

tp_iternext calls it_callable with no arguments and compares the result to it_sentinel using PyObject_RichCompareBool(result, sentinel, Py_EQ). A match raises StopIteration and drops both references. This is the mechanism behind patterns like iter(file.read, b"").

Fast type checks​

#define PySeqIter_Check(op) Py_IS_TYPE((op), &PySeqIter_Type)
#define PyCallIter_Check(op) Py_IS_TYPE((op), &PyCallIter_Type)

Both macros use Py_IS_TYPE, which does an exact type comparison with no subtype walk. That is intentional: neither seqiterobject nor calliterobject is designed to be subclassed.

gopy mirror​

Both iterator structs are ported to objects/seqiter.go.

CPython fieldGo fieldType
si_seqSeq*Object
si_indexIndexint
it_callableCallable*Object
it_sentinelSentinel*Object

The Go types implement tp_iternext via the Iternext method on each receiver. Exhaustion is represented by setting Seq to nil (sequence iterator) or by returning a StopIteration error (call iterator), matching CPython's two different exhaustion signals exactly.

CPython 3.14 changes​

No struct layout changes were made between 3.12 and 3.14 for either iterator type. The 3.13 free-threading work added per-object locks to many core types, but sequence and call iterators were left with the existing GIL-based protection because they are not shared across threads in practice.