- cpython/Objects/methodobject.c
- cpython/Include/methodobject.h
- cpython/Python/bltinmodule.c
- cpython/Objects/call.c
There's a type named builtin_function_or_method in Python. As the type name describes, all built-in functions or methods defined at the C level belong to builtin_function_or_method
>>> print
<built-in function print>
>>> type(print)
<class 'builtin_function_or_method'>Let's read a code snippet first
#define PyCFunction_Check(op) (Py_TYPE(op) == &PyCFunction_Type)
typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
typedef PyObject *(*_PyCFunctionFast) (PyObject *, PyObject *const *, Py_ssize_t);
typedef PyObject *(*PyCFunctionWithKeywords)(PyObject *, PyObject *,
PyObject *);
typedef PyObject *(*_PyCFunctionFastWithKeywords) (PyObject *,
PyObject *const *, Py_ssize_t,
PyObject *);
typedef PyObject *(*PyNoArgsFunction)(PyObject *);PyCFunction is a type in C. Any C function with the signature (accepting two PyObject* as parameters and returning a PyObject*) can be cast to type PyCFunction
// a c function named builtin_print
static PyObject *
builtin_print(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames);
// name "print" is defined inside a c array named builtin_methods, and defined s type PyMethodDef
static PyMethodDef builtin_methods[] = {
...
{"print", (PyCFunction)(void(*)(void))builtin_print, METH_FASTCALL | METH_KEYWORDS, print_doc},
...
}A PyMethodDef should be attached to a module object with a self argument, and then a PyCFunctionObject will be generated.
What the user actually interacts with is PyCFunctionObject
Let's check each field for more detail.
The type in the m_self field is module, and the type in the m_module field is str
As you can see in the above picture, the field ml_name is the name of the built-in method; it's a C-style null-terminated string "print"
The actual C function pointer that does the job
A bit flag that indicates how the C function behaves at the Python level.
The functions in call.c beginning with PyMethodDef will delegate work to the PyCFunction, but with different calling behavior according to different ml_flags
for more detail please refer to c-api Common Object Structures
| flag name | flag value | meaning |
|---|---|---|
| METH_VARARGS | 0x0001 | methods type PyCFunction, expects two PyObject* values |
| METH_KEYWORDS | 0x0002 | methods type PyCFunctionWithKeywords, expects three parameters: self, args, and a dictionary of all the keyword arguments |
| METH_NOARGS | 0x0004 | methods without parameters, need to be of type PyCFunction |
| METH_O | 0x0008 | methods with a single object argument, have the type PyCFunction |
| METH_CLASS | 0x0010 | the type object will be passed as first parameter, what @classmethod do |
| METH_STATIC | 0x0020 | null will passed as first parameter, what @staticmethod do |
| METH_COEXIST | 0x0040 | replace existing defination instead of skip |
static PyCFunctionObject *free_list = NULL;
static int numfree = 0;
#ifndef PyCFunction_MAXFREELIST
#define PyCFunction_MAXFREELIST 256
#endifCPython uses a buffer pool with size 256 to reuse deallocated PyCFunctionObject objects. free_list is a singly linked list; all elements are chained by the m_self field.
A similar technique appears in float objects. Float objects are chained through the ob_type field. I will not draw again; users who need the graphical representation please click the link float(free_list)
They're more related to classobject. I will talk about them later in class object



