Skip to main content

Python/ceval.c (part 93)

Source:

cpython 3.14 @ ab2d84fe1023/Python/ceval.c

This annotation covers function creation opcodes. See python_ceval92_detail for subscript and slice opcodes.

Map

LinesSymbolRole
1-80MAKE_FUNCTIONCreate a PyFunctionObject from a code object
81-160SET_FUNCTION_ATTRIBUTEAttach defaults, annotations, closure
161-240Function object layoutfunc_code, func_defaults, func_closure
241-340CLOSURE / COPY_FREE_VARSHow closures are assembled
341-400Default argument evaluationWhen are default values computed

Reading

MAKE_FUNCTION

// CPython: Python/ceval.c:5880 MAKE_FUNCTION
inst(MAKE_FUNCTION, (codeobj -- func)) {
PyObject *qualname = PEEK(1);
PyFunctionObject *f = (PyFunctionObject *)PyFunction_New(codeobj, GLOBALS());
f->func_qualname = Py_NewRef(qualname);
Py_DECREF(qualname);
func = (PyObject *)f;
}

MAKE_FUNCTION creates a function object from a code object. The globals dict is taken from the current frame. The qualname (e.g., "MyClass.method") is popped from the stack.

SET_FUNCTION_ATTRIBUTE

// CPython: Python/ceval.c:5920 SET_FUNCTION_ATTRIBUTE
inst(SET_FUNCTION_ATTRIBUTE, (attr, func -- func)) {
/* oparg flags:
0x01 = MAKE_FUNCTION_DEFAULTS (positional defaults tuple)
0x02 = MAKE_FUNCTION_KWDEFAULTS (keyword-only defaults dict)
0x04 = MAKE_FUNCTION_ANNOTATIONS (annotations dict)
0x08 = MAKE_FUNCTION_CLOSURE (freevars tuple)
*/
PyFunctionObject *f = (PyFunctionObject *)func;
switch (oparg) {
case 0x01: f->func_defaults = Py_NewRef(attr); break;
case 0x02: f->func_kwdefaults = Py_NewRef(attr); break;
case 0x04: f->func_annotations = Py_NewRef(attr); break;
case 0x08: f->func_closure = Py_NewRef(attr); break;
}
Py_DECREF(attr);
}

SET_FUNCTION_ATTRIBUTE is emitted once per non-None attribute. Default values are evaluated at def time (not call time); this is why def f(x=[]) shares one list across all calls.

Default argument evaluation

def f(x=1+1, y=[]):

LOAD_CONST 2 # 1+1 evaluated at definition
BUILD_LIST 0 # [] created at definition
BUILD_TUPLE 2 # pack into defaults tuple
LOAD_CONST f_code
MAKE_FUNCTION
SET_FUNCTION_ATTRIBUTE 0x01 # attach defaults

Default argument expressions are evaluated once when def executes. The resulting values are stored in func_defaults.

gopy notes

MAKE_FUNCTION is in vm/eval_simple.go and calls objects.NewFunction(code, globals). SET_FUNCTION_ATTRIBUTE sets Function.Defaults, Function.KwDefaults, Function.Annotations, Function.Closure. Default evaluation happens at the def statement, not at the call site.