1
- import collections
2
- import collections .abc
3
1
import threading
2
+ from collections import OrderedDict
3
+ from typing import Any , Callable , Iterator , MutableMapping , Optional , TypeVar
4
4
5
+ K = TypeVar ("K" )
6
+ V = TypeVar ("V" )
5
7
6
- class LRUCache (collections .abc .MutableMapping ):
8
+
9
+ class LRUCache (MutableMapping [K , V ]):
7
10
"""Thread-safe LRUCache based on an OrderedDict.
8
11
9
12
All dict operations (__getitem__, __setitem__, __contains__) update the
@@ -18,7 +21,14 @@ class LRUCache(collections.abc.MutableMapping):
18
21
the cache, e.g., ``cache.maxsize = new_size``.
19
22
"""
20
23
21
- def __init__ (self , maxsize , on_evict = None ):
24
+ _cache : "OrderedDict[K, V]"
25
+ _maxsize : int
26
+ _lock : threading .RLock
27
+ _on_evict : Optional [Callable [[K , V ], Any ]]
28
+
29
+ __slots__ = ("_cache" , "_lock" , "_maxsize" , "_on_evict" )
30
+
31
+ def __init__ (self , maxsize : int , on_evict : Callable [[K , V ], Any ] = None ):
22
32
"""
23
33
Parameters
24
34
----------
@@ -33,25 +43,26 @@ def __init__(self, maxsize, on_evict=None):
33
43
if maxsize < 0 :
34
44
raise ValueError ("maxsize must be non-negative" )
35
45
self ._maxsize = maxsize
36
- self ._on_evict = on_evict
37
- self ._cache = collections .OrderedDict ()
46
+ self ._cache = OrderedDict ()
38
47
self ._lock = threading .RLock ()
48
+ self ._on_evict = on_evict
39
49
40
- def __getitem__ (self , key ) :
50
+ def __getitem__ (self , key : K ) -> V :
41
51
# record recent use of the key by moving it to the front of the list
42
52
with self ._lock :
43
53
value = self ._cache [key ]
44
54
self ._cache .move_to_end (key )
45
55
return value
46
56
47
- def _enforce_size_limit (self , capacity ):
48
- """Shrink the cache if necessary, evicting the oldest items."""
57
+ def _enforce_size_limit (self , capacity : int ) -> None :
58
+ """Shrink the cache if necessary, evicting the oldest items.
59
+ """
49
60
while len (self ._cache ) > capacity :
50
61
key , value = self ._cache .popitem (last = False )
51
62
if self ._on_evict is not None :
52
63
self ._on_evict (key , value )
53
64
54
- def __setitem__ (self , key , value ) :
65
+ def __setitem__ (self , key : K , value : V ) -> None :
55
66
with self ._lock :
56
67
if key in self ._cache :
57
68
# insert the new value at the end
@@ -65,24 +76,24 @@ def __setitem__(self, key, value):
65
76
# not saving, immediately evict
66
77
self ._on_evict (key , value )
67
78
68
- def __delitem__ (self , key ) :
79
+ def __delitem__ (self , key : K ) -> None :
69
80
del self ._cache [key ]
70
81
71
- def __iter__ (self ):
82
+ def __iter__ (self ) -> Iterator [ K ] :
72
83
# create a list, so accessing the cache during iteration cannot change
73
84
# the iteration order
74
85
return iter (list (self ._cache ))
75
86
76
- def __len__ (self ):
87
+ def __len__ (self ) -> int :
77
88
return len (self ._cache )
78
89
79
90
@property
80
- def maxsize (self ):
91
+ def maxsize (self ) -> int :
81
92
"""Maximum number of items can be held in the cache."""
82
93
return self ._maxsize
83
94
84
95
@maxsize .setter
85
- def maxsize (self , size ) :
96
+ def maxsize (self , size : int ) -> None :
86
97
"""Resize the cache, evicting the oldest items if necessary."""
87
98
if size < 0 :
88
99
raise ValueError ("maxsize must be non-negative" )
0 commit comments