@@ -13,7 +13,7 @@ If you like this work, please [star](https://github.com/lonelyenvoy/python-memoi
1313## Why choose this library?
1414
1515Perhaps 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
1818Well, 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 ,))
60613430019387558
61- >> > hash (3430019387558.0 ) # two different arguments have an identical hash value
62+ >> > hash (3430019387558.0 ) # two different arguments with an identical hash value
62633430019387558
6364```
6465
@@ -186,7 +187,7 @@ Example:
186187
187188``` python
188189def 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)
192193def 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
2303851 . ** Q: There are duplicated code in ` memoization ` and most of them can be eliminated by using another level of
231386abstraction (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
2383932 . ** 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
0 commit comments