Skip to main content

Include/cpython/methodobject.h

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

Map

methodobject.h is split across two headers in CPython's include layout. The stable ABI surface (PyMethodDef, PyCFunction, METH_* flags) lives in Include/methodobject.h. The internal-only struct layout and access macros live here in Include/cpython/methodobject.h.

SymbolKindPurpose
PyMethodDefstructDescribes one C-implemented method: name, pointer, flags, docstring
PyCFunctionObjectstructThe Python object wrapping a PyMethodDef at runtime
PyCFunction_GET_FUNCTIONmacroReads m_ml->ml_meth from a PyCFunctionObject *
PyCFunction_GET_SELFmacroReads m_self (the bound instance, or NULL for unbound)
PyCFunction_GET_FLAGSmacroReads m_ml->ml_flags
PyCFunction_GET_MODULEmacroReads m_module (the module the function belongs to)

PyMethodDef fields

FieldTypeMeaning
ml_nameconst char *Method name exposed to Python
ml_methPyCFunctionC function pointer
ml_flagsintCombination of METH_* flags
ml_docconst char *Docstring (may be NULL)

PyCFunctionObject fields

FieldMeaning
m_mlPointer to the PyMethodDef
m_selfBound self object, or NULL
m_moduleModule object, or NULL
m_weakreflistWeak-reference list head
vectorcallvectorcallfunc slot, filled when METH_FASTCALL is set

METH_* flags

FlagValueMeaning
METH_VARARGS0x0001Called as f(self, args) where args is a tuple
METH_KEYWORDS0x0002Called as f(self, args, kwargs)
METH_NOARGS0x0004Called as f(self, NULL); accepts no arguments
METH_O0x0008Called as f(self, arg) with exactly one argument
METH_CLASS0x0010Receives the class as self instead of an instance
METH_STATIC0x0020Receives no implicit first argument
METH_FASTCALL0x0080Vectorcall convention: f(self, args, nargs, kwnames)

METH_CLASS and METH_STATIC are mutually exclusive. METH_FASTCALL may be combined with METH_KEYWORDS to enable METH_FASTCALL | METH_KEYWORDS.

Reading

Struct layout

The two structs are deliberately compact. PyMethodDef is a plain C struct with no PyObject_HEAD; it is not a Python object itself. PyCFunctionObject wraps it at runtime:

// Include/methodobject.h (stable ABI portion)
struct PyMethodDef {
const char *ml_name;
PyCFunction ml_meth;
int ml_flags;
const char *ml_doc;
};
// Include/cpython/methodobject.h (internal portion)
struct PyCFunctionObject {
PyObject_HEAD
PyMethodDef *m_ml; /* Description of the C function to call */
PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */
PyObject *m_module; /* The __module__ attribute, can be anything */
PyObject *m_weakreflist;
vectorcallfunc vectorcall;
};

The vectorcall field was added in 3.9. When it is non-NULL, the call machinery uses the vectorcall protocol instead of going through PyCFunction_Call, which avoids building a temporary argument tuple.

Access macros

The three main accessor macros read fields through a cast rather than through direct member access, so calling code does not depend on the exact struct layout:

// Include/cpython/methodobject.h
#define PyCFunction_GET_FUNCTION(func) \
(((PyCFunctionObject *)func)->m_ml->ml_meth)

#define PyCFunction_GET_SELF(func) \
(((PyCFunctionObject *)func)->m_self)

#define PyCFunction_GET_FLAGS(func) \
(((PyCFunctionObject *)func)->m_ml->ml_flags)

All three macros evaluate their argument twice, so passing an expression with side effects is unsafe.

Calling convention dispatch

The call path in Objects/call.c inspects ml_flags to decide how to invoke the C function. The fast path for METH_FASTCALL | METH_KEYWORDS avoids any tuple allocation:

// Objects/methodobject.c
static PyObject *
cfunction_vectorcall_FASTCALL_KEYWORDS(
PyObject *func, PyObject *const *stack,
size_t nargsf, PyObject *kwnames)
{
PyCFunctionObject *cf = (PyCFunctionObject *)func;
_PyCFunctionFastWithKeywords meth =
(_PyCFunctionFastWithKeywords)(void(*)(void))cf->m_ml->ml_meth;
PyObject *self = cf->m_self;
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
return meth(self, stack, nargs, kwnames);
}

This is the path taken by most built-in methods in 3.14; the older METH_VARARGS path is still supported for extension modules that have not been updated.

gopy mirror

Ported to /Users/apple/github/tamnd/gopy/objects/method.go.

PyMethodDef maps to MethodDef and PyCFunctionObject maps to CFunction. The METH_* constants are defined as const iota-style values. The three access macros become methods on the CFunction type: GetFunction, GetSelf, and GetFlags. The vectorcall slot is present and is wired into gopy's call dispatch in vm/eval_call.go.

CPython 3.14 changes

3.14 added METH_STACKLESS as an internal flag used by Stackless-aware builds; it is not part of the stable ABI. The PyCFunctionObject struct gained a second vectorcall path for methods that carry a self argument from __init_subclass__ and similar hooks. The access macros are unchanged.