Skip to content

Commit 1f4267e

Browse files
committed
update readme
1 parent 71862e2 commit 1f4267e

File tree

2 files changed

+167
-12
lines changed

2 files changed

+167
-12
lines changed

README.md

Lines changed: 166 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ If you like this work, please [star](https://github.com/lonelyenvoy/python-memoi
1313
## Why choose this library?
1414

1515
Perhaps you know about [```functools.lru_cache```](https://docs.python.org/3/library/functools.html#functools.lru_cache)
16-
in Python 3, and you may be wondering why I am reinventing the wheel.
16+
in Python 3, and you may be wondering why we are reinventing the wheel.
1717

1818
Well, actually not. This lib is based on ```functools```. Please find below the comparison with ```lru_cache```.
1919

@@ -30,7 +30,8 @@ Well, actually not. This lib is based on ```functools```. Please find below the
3030
|TTL (Time-To-Live) support|No support|✔️|
3131
|Support for unhashable arguments (dict, list, etc.)|No support|✔️|
3232
|Custom cache keys|No support|✔️|
33-
|Partial cache clearing|No support|Pending implementation in v0.3.x|
33+
|On-demand partial cache clearing|No support|✔️|
34+
|Iterating through the cache|No support|✔️|
3435
|Python version|3.2+|3.4+|
3536

3637
```memoization``` solves some drawbacks of ```functools.lru_cache```:
@@ -58,7 +59,7 @@ TypeError: unhashable type: 'list'
5859
```python
5960
>>> hash((1,))
6061
3430019387558
61-
>>> hash(3430019387558.0) # two different arguments have an identical hash value
62+
>>> hash(3430019387558.0) # two different arguments with an identical hash value
6263
3430019387558
6364
```
6465

@@ -186,7 +187,7 @@ Example:
186187

187188
```python
188189
def get_employee_id(employee):
189-
return employee.id
190+
return employee.id # returns a string or a integer
190191

191192
@cached(custom_key_maker=get_employee_id)
192193
def calculate_performance(employee):
@@ -221,18 +222,172 @@ With ```cache_info```, you can retrieve the number of ```hits``` and ```misses``
221222

222223
### Other APIs
223224

224-
- Access the original function ```f``` by ```f.__wrapped__```.
225-
- Clear the cache by ```f.cache_clear()```.
226-
- Disable `SyntaxWarning` by ```memoization.suppress_warnings()```.
225+
- Access the original undecorated function `f` by `f.__wrapped__`.
226+
- Check whether the cache is empty by `f.cache_is_empty()`.
227+
- Check whether the cache is full by `f.cache_is_full()`.
228+
- Disable `SyntaxWarning` by `memoization.suppress_warnings()`.
229+
230+
## Advanced API References
231+
232+
### Checking whether the cache contains something
233+
234+
#### cache_contains_argument(function_arguments, alive_only)
235+
236+
```
237+
Return True if the cache contains a cached item with the specified function call arguments
238+
239+
:param function_arguments: Can be a list, a tuple or a dict.
240+
- Full arguments: use a list to represent both positional arguments and keyword
241+
arguments. The list contains two elements, a tuple (positional arguments) and
242+
a dict (keyword arguments). For example,
243+
f(1, 2, 3, a=4, b=5, c=6)
244+
can be represented by:
245+
[(1, 2, 3), {'a': 4, 'b': 5, 'c': 6}]
246+
- Positional arguments only: when the arguments does not include keyword arguments,
247+
a tuple can be used to represent positional arguments. For example,
248+
f(1, 2, 3)
249+
can be represented by:
250+
(1, 2, 3)
251+
- Keyword arguments only: when the arguments does not include positional arguments,
252+
a dict can be used to represent keyword arguments. For example,
253+
f(a=4, b=5, c=6)
254+
can be represented by:
255+
{'a': 4, 'b': 5, 'c': 6}
256+
257+
:param alive_only: Whether to check alive cache item only (default to True).
258+
259+
:return: True if the desired cached item is present, False otherwise.
260+
```
261+
262+
#### cache_contains_result(return_value, alive_only)
263+
264+
```
265+
Return True if the cache contains a cache item with the specified user function return value. O(n) time
266+
complexity.
267+
268+
:param return_value: A return value coming from the user function.
269+
270+
:param alive_only: Whether to check alive cache item only (default to True).
271+
272+
:return: True if the desired cached item is present, False otherwise.
273+
```
274+
275+
### Iterating through the cache
276+
277+
#### cache_arguments()
278+
279+
```
280+
Get user function arguments of all alive cache elements
281+
282+
see also: cache_items()
283+
284+
Example:
285+
@cached
286+
def f(a, b, c, d):
287+
...
288+
f(1, 2, c=3, d=4)
289+
for argument in f.cache_arguments():
290+
print(argument) # ((1, 2), {'c': 3, 'd': 4})
291+
292+
:return: an iterable which iterates through a list of a tuple containing a tuple (positional arguments) and
293+
a dict (keyword arguments)
294+
```
295+
296+
#### cache_results()
297+
298+
```
299+
Get user function return values of all alive cache elements
300+
301+
see also: cache_items()
302+
303+
Example:
304+
@cached
305+
def f(a):
306+
return a
307+
f('hello')
308+
for result in f.cache_results():
309+
print(result) # 'hello'
310+
311+
:return: an iterable which iterates through a list of user function result (of any type)
312+
```
313+
314+
#### cache_items()
315+
316+
```
317+
Get cache items, i.e. entries of all alive cache elements, in the form of (argument, result).
318+
319+
argument: a tuple containing a tuple (positional arguments) and a dict (keyword arguments).
320+
result: a user function return value of any type.
321+
322+
see also: cache_arguments(), cache_results().
323+
324+
Example:
325+
@cached
326+
def f(a, b, c, d):
327+
return 'the answer is ' + str(a)
328+
f(1, 2, c=3, d=4)
329+
for argument, result in f.cache_items():
330+
print(argument) # ((1, 2), {'c': 3, 'd': 4})
331+
print(result) # 'the answer is 1'
332+
333+
:return: an iterable which iterates through a list of (argument, result) entries
334+
```
335+
336+
#### cache_for_each()
337+
338+
```
339+
Perform the given action for each cache element in an order determined by the algorithm until all
340+
elements have been processed or the action throws an error
341+
342+
:param consumer: an action function to process the cache elements. Must have 3 arguments:
343+
def consumer(user_function_arguments, user_function_result, is_alive): ...
344+
user_function_arguments is a tuple holding arguments in the form of (args, kwargs).
345+
args is a tuple holding positional arguments.
346+
kwargs is a dict holding keyword arguments.
347+
for example, for a function: foo(a, b, c, d), calling it by: foo(1, 2, c=3, d=4)
348+
user_function_arguments == ((1, 2), {'c': 3, 'd': 4})
349+
user_function_result is a return value coming from the user function.
350+
is_alive is a boolean value indicating whether the cache is still alive
351+
(if a TTL is given).
352+
```
353+
354+
### Removing something from the cache
355+
356+
#### cache_clear()
357+
358+
```
359+
Clear the cache and its statistics information
360+
```
361+
362+
#### cache_remove_if(predicate)
363+
364+
```
365+
Remove all cache elements that satisfy the given predicate
366+
367+
:param predicate: a predicate function to judge whether the cache elements should be removed. Must
368+
have 3 arguments, and returns True or False:
369+
def consumer(user_function_arguments, user_function_result, is_alive): ...
370+
user_function_arguments is a tuple holding arguments in the form of (args, kwargs).
371+
args is a tuple holding positional arguments.
372+
kwargs is a dict holding keyword arguments.
373+
for example, for a function: foo(a, b, c, d), calling it by: foo(1, 2, c=3, d=4)
374+
user_function_arguments == ((1, 2), {'c': 3, 'd': 4})
375+
user_function_result is a return value coming from the user function.
376+
is_alive is a boolean value indicating whether the cache is still alive
377+
(if a TTL is given).
378+
379+
:return: True if at least one element is removed, False otherwise.
380+
```
381+
227382

228383
## Q&A
229384

230385
1. **Q: There are duplicated code in `memoization` and most of them can be eliminated by using another level of
231386
abstraction (e.g. classes and multiple inheritance). Why not refactor?**
232387

233388
A: We would like to keep the code in a proper level of abstraction. However, these abstractions make it run slower.
234-
As this is a caching library focusing on speed, we have to give up some elegance for better performance. We consider
235-
refactoring for better code maintainability while keeping good performance as a future work.
389+
As this is a caching library focusing on speed, we have to give up some elegance for better performance. Refactoring
390+
is our future work.
236391

237392

238393
2. **Q: I have submitted an issue and not received a reply for a long time. Anyone can help me?**
@@ -258,8 +413,8 @@ This project welcomes contributions from anyone.
258413
[pythonsvg]: https://img.shields.io/pypi/pyversions/memoization.svg
259414
[python]: https://www.python.org
260415

261-
[travismaster]: https://travis-ci.org/lonelyenvoy/python-memoization.svg?branch=master
262-
[travis]: https://travis-ci.org/lonelyenvoy/python-memoization
416+
[travismaster]: https://travis-ci.com/lonelyenvoy/python-memoization.svg?branch=master
417+
[travis]: https://travis-ci.com/lonelyenvoy/python-memoization
263418

264419
[coverallssvg]: https://coveralls.io/repos/github/lonelyenvoy/python-memoization/badge.svg?branch=master
265420
[coveralls]: https://coveralls.io/github/lonelyenvoy/python-memoization?branch=master

memoization/type/model.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ class CachedFunction(Protocol[T]):
118118
"""
119119

120120
def cache_items(self) -> Iterable[Tuple[Tuple[Tuple, Dict], Any]]:
121-
"""
121+
"""
122122
Get cache items, i.e. entries of all alive cache elements, in the form of (argument, result).
123123
124124
argument: a tuple containing a tuple (positional arguments) and a dict (keyword arguments).

0 commit comments

Comments
 (0)