Skip to main content

Python/ceval.c (part 28)

Source:

cpython 3.14 @ ab2d84fe1023/Python/ceval.c

This annotation covers pattern matching and async iteration opcodes. See python_ceval27_detail for import opcodes.

Map

LinesSymbolRole
1-80MATCH_MAPPINGcase {key: val}: — check for __keys__ protocol
81-180MATCH_SEQUENCEcase [a, b]: — check for sequence protocol (not str/bytes)
181-280MATCH_KEYSExtract keys from a mapping for pattern matching
281-380GET_ITERCall iter() on TOS; used by for loops
381-500GET_AITER / GET_ANEXTAsync iteration: async for

Reading

MATCH_MAPPING

// CPython: Python/ceval.c:5620 MATCH_MAPPING
inst(MATCH_MAPPING, (subject -- subject, res)) {
/* A "mapping" for match purposes: has Py_TPFLAGS_MAPPING set,
OR has __keys__ in its type's __mro__. */
int match = PyType_HasFeature(Py_TYPE(subject), Py_TPFLAGS_MAPPING);
if (!match) {
PyObject *keys = _PyObject_LookupAttr(Py_TYPE(subject), &_Py_ID(keys));
match = (keys != NULL);
Py_XDECREF(keys);
}
res = match ? Py_True : Py_False;
Py_INCREF(res);
}

case {'x': x}: first checks if the subject is a mapping. dict has Py_TPFLAGS_MAPPING set. Custom types can opt in by setting the flag or having a keys method. Strings and bytes have Py_TPFLAGS_SEQUENCE and are excluded from mapping patterns.

MATCH_KEYS

// CPython: Python/ceval.c:5700 MATCH_KEYS
inst(MATCH_KEYS, (subject, keys -- subject, keys, values_or_none)) {
/* Extract all keys from subject; push tuple of values or None on failure. */
PyObject *values_or_none = _PyEval_MatchKeys(tstate, subject, keys);
if (values_or_none == NULL) ERROR_IF(true, error);
}

_PyEval_MatchKeys calls subject.get(key, sentinel) for each key. If any key is missing (returns sentinel), it returns None to indicate a failed match. Otherwise returns a tuple of values.

GET_AITER

// CPython: Python/ceval.c:5820 GET_AITER
inst(GET_AITER, (obj -- iter)) {
/* Async for: get the async iterator via __aiter__ */
PyObject *awaitable = type->tp_as_async->am_aiter(obj);
if (awaitable == NULL) ERROR_IF(true, error);
/* If __aiter__ returned a coroutine (old protocol), deprecate it */
if (PyCoro_CheckExact(awaitable)) {
... /* DeprecationWarning */
}
iter = awaitable;
}

async for x in obj: calls obj.__aiter__() to get the async iterator. The iterator must implement __anext__() which returns an awaitable.

gopy notes

MATCH_MAPPING is vm.MatchMapping in vm/eval_gen.go. It checks objects.TypeHasFlags(Py_TPFLAGS_MAPPING) or a keys attribute. MATCH_KEYS calls vm.MatchKeys which uses objects.CallMethod(subject, "get", key, sentinel). GET_AITER calls objects.AsyncIter. GET_ANEXT calls objects.AsyncNext.