New submission from Benoit B <[email protected]>:
I don't know if I'm missing something, but there's a behavior of
functools.lru_cache() that I currently don't understand.
As the documentation states:
"If typed is set to true, function arguments of different types will be cached
separately. For example, f(3) and f(3.0) will be treated as distinct calls with
distinct results."
For a function accepting only positional arguments, using typed=False doesn't
seem to be working in all cases.
>>> import functools
>>>
>>> @functools.lru_cache() # Implicitly uses typed=False
>>> def func(a):
... return a
>>>
>>> func(1)
>>> func(1.0)
>>>
>>> print(func.cache_info())
CacheInfo(hits=0, misses=2, maxsize=128, currsize=2)
Instead, I would have expected: CacheInfo(hits=1, misses=1, maxsize=128,
currsize=2)
So it looks like 1 and 1.0 were stored as different values even though
typed=False was used.
After analyzing the source code of _functoolsmodule.c::lru_cache_make_key(), I
found what follows:
if (!typed && !kwds_size) {
if (PyTuple_GET_SIZE(args) == 1) {
key = PyTuple_GET_ITEM(args, 0);
if (PyUnicode_CheckExact(key) || PyLong_CheckExact(key)) { <<<
it appears that a 'float' would cause 'args' (a tuple) to be returned as the
key, whereas an 'int' would cause 'key'
/* For common scalar keys, save space by
(an int) to be returned as the key. So 1 and 1.0 generate different hashes and
are stored as different items.
dropping the enclosing args tuple */
Py_INCREF(key);
return key;
}
}
Py_INCREF(args);
return args;
}
At some point in the past, the above code section looked like this:
if (!typed && !kwds) {
Py_INCREF(args);
return args;
}
So no matter what the type of the argument was, it was working.
Am I somehow mistaken in my analysis or is this a bug?
----------
components: Library (Lib)
messages: 361404
nosy: bbernard
priority: normal
severity: normal
status: open
title: @functools.lru_cache() not respecting typed=False
type: behavior
versions: Python 3.8
_______________________________________
Python tracker <[email protected]>
<https://bugs.python.org/issue39554>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com