Skip to main content

Modules/_functoolsmodule.c (part 6)

Source:

cpython 3.14 @ ab2d84fe1023/Modules/_functoolsmodule.c

This annotation covers the C-level lru_cache implementation. See lib_functools5_detail for the Python-level lru_cache algorithm description.

Map

LinesSymbolRole
1-80_lru_cache_wrapper typeC struct holding the cache state
81-180lru_cache_callCache lookup and call dispatch
181-280make_key in CHash args into a cache key
281-360LRU list manipulationMove-to-front and eviction in C
361-500cache_info / cache_clear CStatistics and reset

Reading

lru_cache_call

// CPython: Modules/_functoolsmodule.c:820 lru_cache_call
static PyObject *
lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
{
PyObject *key = make_key(self, args, kwds);
/* Lookup in the cache dict */
lru_list_elem *link = (lru_list_elem *)PyDict_GetItemWithError(self->cache, key);
if (link != NULL) {
/* Cache hit: move to front of LRU list */
lru_cache_move_link_to_front(self, link);
self->hits++;
PyObject *result = Py_NewRef(link->result);
Py_DECREF(key);
return result;
}
/* Cache miss: call the wrapped function */
PyObject *result = PyObject_Call(self->func, args, kwds);
if (self->maxsize > 0 && PyDict_GET_SIZE(self->cache) >= self->maxsize) {
/* Evict LRU entry */
lru_cache_evict(self);
}
lru_cache_append(self, key, result);
self->misses++;
return result;
}

The C implementation avoids Python interpreter overhead for the cache lookup. The LRU list is a circular doubly linked list of lru_list_elem structs. Cache hits are the fast path: one dict lookup + pointer manipulation.

make_key in C

// CPython: Modules/_functoolsmodule.c:680 make_key
static PyObject *
make_key(lru_cache_object *self, PyObject *args, PyObject *kwds)
{
/* Build a hashable key from args and kwds */
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
Py_ssize_t nkwds = kwds ? PyDict_GET_SIZE(kwds) : 0;
if (nkwds == 0 && !self->typed) {
/* Fast path: single arg or tuple key */
if (nargs == 1) {
PyObject *arg = PyTuple_GET_ITEM(args, 0);
if (PyUnicode_CheckExact(arg) || PyLong_CheckExact(arg))
return Py_NewRef(arg);
}
return Py_NewRef(args);
}
/* General case: build a combined tuple */
...
}

Single-int and single-string keys bypass tuple creation for maximum speed. Combined tuples for multi-arg calls are built by extending the args tuple with keyword pairs.

gopy notes

The C _lru_cache_wrapper is module/functools.CacheLRU in module/functools/module.go. The LRU list is a lruList struct with head and tail pointers. make_key uses objects.TupleNew for multi-arg keys and direct object references for single-primitive keys. Cache stats are atomic counters.