tkem/cachetools

Cache implementations and the "in" operator / __contains__ method

Closed this issue · 2 comments

Consider the following examples:

from cachetools import LRUCache

cache = LRUCache(2)
cache[1] = 1
cache[2] = 2
cache[1]  # get first key
cache[3] = 3
cache

Expected and actual result:

LRUCache([(1, 1), (3, 3)], maxsize=2, currsize=2)

But if you use the in operator or the __contains__ method instead, this doesn't count as usage:

from cachetools import LRUCache

cache = LRUCache(2)
cache[1] = 1
cache[2] = 2
1 in cache  # lookup first key
cache[3] = 3
cache

Expected result:

LRUCache([(1, 1), (3, 3)], maxsize=2, currsize=2)

Actual result:

LRUCache([(2, 2), (3, 3)], maxsize=2, currsize=2)

Hanse the question -- is this by design?
I saw only one other kinda-related issue #26, which is the opposite case of this one -- missing vs contains.

tkem commented

Yes, using the in operator doesn't count as usage and should not affect caching behavior.
It surely can be argued both ways, but frankly it just never occurred to me that __contains__() could be seen as "accessing" the cached item.

Thank you for answering. My use case requires this behavior, so I wanted to know if this is by design.
Example with lookup (this use case doesn't care about the actual stored value):

from cachetools import LRUCache


class LookupCache(LRUCache):
    def __contains__(self, key):
        found = super().__contains__(key)
        self[key] = None
        return found


cache = LookupCache(2)
cache[1] = 1
cache[2] = 2
1 in cache  # lookup first key
cache[3] = 3
cache