Skip to main content

Python/ceval.c (part 13)

Source:

cpython 3.14 @ ab2d84fe1023/Python/ceval.c

This annotation covers import opcodes and collection building. See python_ceval12_detail for closure opcodes, and python_ceval_detail for the eval loop.

Map

LinesSymbolRole
1-100IMPORT_NAMEExecute import foo — calls __import__
101-200IMPORT_FROMExecute from foo import bargetattr(module, 'bar')
201-280IMPORT_STARExecute from foo import * — copy __all__ or all public names
281-380BUILD_MAPBuild a dict from N key-value pairs on the stack
381-460BUILD_SETBuild a set from N items on the stack
461-600DICT_UPDATE / SET_UPDATEMerge an iterable/mapping into an existing dict/set

Reading

IMPORT_NAME

// CPython: Python/ceval.c:3280 IMPORT_NAME
inst(IMPORT_NAME, (level, fromlist -- res)) {
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
res = import_name(tstate, frame, name, fromlist, level);
ERROR_IF(res == NULL, error);
}

static PyObject *
import_name(PyThreadState *tstate, _PyInterpreterFrame *frame,
PyObject *name, PyObject *fromlist, PyObject *level)
{
/* Call builtins.__import__(name, globals, locals, fromlist, level) */
PyObject *import_func = _PyDict_GetItemWithError(
frame->f_builtins, &_Py_ID(__import__));
return PyObject_Call(import_func,
PyTuple_Pack(5, name, globals, locals, fromlist, level), NULL);
}

import foo.bar pushes level=0, fromlist=None, then IMPORT_NAME calls builtins.__import__. The returned module is the top-level package (foo), not foo.bar.

IMPORT_FROM

// CPython: Python/ceval.c:3340 IMPORT_FROM
inst(IMPORT_FROM, (from -- from, res)) {
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
res = import_from(tstate, from, name);
ERROR_IF(res == NULL, error);
}

static PyObject *
import_from(PyThreadState *tstate, PyObject *v, PyObject *name)
{
/* Try v.name, then v.__path__ sub-import */
PyObject *x = PyObject_GetAttr(v, name);
if (x == NULL && _PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
/* Package: try importing v.name as a submodule */
PyObject *fullmodname = PyUnicode_FromFormat("%U.%U",
PyObject_GetAttrString(v, "__name__"), name);
x = PyDict_GetItemWithError(tstate->interp->modules, fullmodname);
}
return x;
}

from foo import bar — if foo.bar is not an attribute of foo, try looking it up in sys.modules as a sub-module.

IMPORT_STAR

// CPython: Python/ceval.c:3380 IMPORT_STAR
inst(IMPORT_STAR, (from --)) {
/* Copy all names from 'from' into the current local namespace.
If __all__ is defined, use it; otherwise copy all non-_ names. */
PyObject *all = PyObject_GetAttr(from, &_Py_ID(__all__));
if (all != NULL) {
for each name in all: STORE_NAME(name, getattr(from, name));
} else {
for each name in dir(from):
if (!name.startswith('_')):
STORE_NAME(name, getattr(from, name));
}
}

from foo import * is only valid at module scope. The compiler raises a SyntaxWarning if used inside a function (because it would corrupt co_varnames).

BUILD_MAP

// CPython: Python/ceval.c:3480 BUILD_MAP
inst(BUILD_MAP, (values[oparg*2] -- map)) {
map = _PyDict_FromItems(values, 2, values+1, 2, oparg);
ERROR_IF(map == NULL, error);
DECREF_INPUTS();
}

{k1: v1, k2: v2} is compiled to LOAD k1, LOAD v1, LOAD k2, LOAD v2, BUILD_MAP 2. The interleaved key-value pairs are collected from the stack.

DICT_UPDATE

// CPython: Python/ceval.c:3560 DICT_UPDATE
inst(DICT_UPDATE, (update --)) {
/* dict_to_update |= update, used for {**d1, **d2} */
PyObject *dict = PEEK(oparg + 1);
if (PyDict_Update(dict, update) < 0) {
if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
_PyErr_Format(tstate, PyExc_TypeError,
"'%.200s' object is not a mapping",
Py_TYPE(update)->tp_name);
}
ERROR_IF(true, error);
}
}

{**d1, **d2} compiles to BUILD_MAP 0, DICT_UPDATE 1 (for d1), DICT_UPDATE 1 (for d2). The oparg is the stack depth of the target dict.

gopy notes

IMPORT_NAME calls vm.ImportName which invokes builtins.__import__ via objects.Call. IMPORT_FROM is vm.ImportFrom. BUILD_MAP is vm.BuildMap using objects.NewDictFromItems. DICT_UPDATE uses objects.DictUpdate. SET_UPDATE uses objects.SetUpdate.