File: cache.py

package info (click to toggle)
orange3 3.40.0-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 15,912 kB
  • sloc: python: 162,745; ansic: 622; makefile: 322; sh: 93; cpp: 77
file content (85 lines) | stat: -rw-r--r-- 2,528 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
"""Common caching methods, using `lru_cache` sometimes has its downsides."""
from functools import wraps, lru_cache
from typing import MutableMapping
import weakref


def single_cache(func):
    """Cache with size 1."""
    last_args = ()
    last_kwargs = set()
    last_result = None

    @wraps(func)
    def _cached(*args, **kwargs):
        nonlocal last_args, last_kwargs, last_result
        if len(last_args) != len(args) or \
                not all(x is y for x, y in zip(args, last_args)) or \
                last_kwargs != set(kwargs) or \
                any(last_kwargs[k] != kwargs[k] for k in last_kwargs):
            last_result = func(*args, **kwargs)
            last_args, last_kwargs = args, kwargs
        return last_result

    return _cached


def memoize_method(*lru_args, **lru_kwargs):
    """Memoize methods without keeping reference to `self`.

    Using ordinary lru_cache on methods keeps a reference to the object in the cache,
    creating a cycle that keeps the object from getting garbage collected.

    Parameters
    ----------
    lru_args
    lru_kwargs

    See Also
    --------
    https://stackoverflow.com/questions/33672412/python-functools-lru-cache-with-class-methods-release-object

    """
    def _decorator(func):

        @lru_cache(*lru_args, **lru_kwargs)
        def _cached_method(self_weak, *args, **kwargs):
            return func(self_weak(), *args, **kwargs)

        @wraps(func)
        def _wrapped_func(self, *args, **kwargs):
            return _cached_method(weakref.ref(self), *args, **kwargs)

        _wrapped_func.cache_clear = _cached_method.cache_clear
        _wrapped_func.cache_info = _cached_method.cache_info
        return _wrapped_func

    return _decorator


class IDWeakrefCache:
    """
    Cache that caches keys according to their id() for speed. It also stores
    weak references to the keys to ensure that the same keys are being accessed.
    """

    def __init__(self, cache: MutableMapping):
        self._cache = cache

    def __setitem__(self, keys, value):
        self._cache[tuple(map(id, keys))] = \
            value, [weakref.ref(k) for k in keys]

    def __getitem__(self, keys):
        key = tuple(map(id, keys))
        if key not in self._cache:
            raise KeyError()
        shared, weakrefs = self._cache[key]
        for r in weakrefs:
            if r() is None:
                del self._cache[key]
                raise KeyError()
        return shared

    def clear(self):
        self._cache.clear()