Skip to main content

Modules/_functoolsmodule.c (part 2)

cpython 3.14 @ ab2d84fe1023/Modules/_functoolsmodule.c

This annotation covers lru_cache, reduce, and cmp_to_key in _functoolsmodule.c. For partial and the basic module structure see the module_functools annotation.

Map

LinesSymbolRole
1-400lru_cache_object, lru_cache_callBounded LRU cache with typed/untyped keys
401-700lru_list_elemDoubly-linked list node for LRU eviction order
701-900cache_info, cache_clearHit/miss statistics and cache reset
901-1200functools_reduce_implLeft fold over an iterable
1201-1600cmp_to_key, KeyWrapperConvert old-style comparison function to key function

Reading

lru_cache doubly-linked dict

The cache is a dict from cache key to lru_list_elem node. Nodes form a doubly-linked list in LRU order. On cache hit, the node is moved to the front. On cache miss (if the cache is full), the least-recently-used node (tail) is evicted from both the dict and the list.

// CPython: Modules/_functoolsmodule.c:848 lru_cache_call
static PyObject *
lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
{
...
link = (lru_list_elem *)PyDict_GetItemWithError(self->cache, key);
if (link != NULL) {
/* cache hit: move to front */
lru_cache_unlink_result(link);
lru_cache_prepend_link(self, link);
self->hits++;
return Py_NewRef(link->result);
}
...
}

typed cache keys

When lru_cache(typed=True), the cache key includes the argument types. 1 and 1.0 hash equally but have different types, so they get separate cache entries.

reduce

functools.reduce(function, iterable[, initializer]) applies function cumulatively. If initializer is absent, the first element of the iterable is used as the initial value.

// CPython: Modules/_functoolsmodule.c:1050 functools_reduce_impl
static PyObject *
functools_reduce_impl(PyObject *module, PyObject *func, PyObject *seq,
PyObject *result)
{
...
while ((op = PyIter_Next(it)) != NULL) {
newresult = PyObject_CallFunctionObjArgs(func, result, op, NULL);
...
result = newresult;
}
...
}

cmp_to_key

cmp_to_key(mycmp) returns a class K whose __lt__, __gt__, etc. call mycmp(a, b) and compare the result to 0. This adapts old-style comparison functions for use with sorted(key=...).

gopy notes

module/functools/ is partially ported. lru_cache is not yet implemented; it requires an LRU dict structure. reduce and cmp_to_key are simpler and are on the roadmap.