From 9eb2facbd513fc25fc18f33571a8f609a9ff577c Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Fri, 2 May 2025 16:33:15 +0800 Subject: [PATCH 1/2] Make flexicache LRU instead of FIFO --- fastcore/xtras.py | 3 +- nbs/03_xtras.ipynb | 141 +++++++++++++++++++++++++++------------------ 2 files changed, 86 insertions(+), 58 deletions(-) diff --git a/fastcore/xtras.py b/fastcore/xtras.py index 5d76c0c7..512cbf97 100644 --- a/fastcore/xtras.py +++ b/fastcore/xtras.py @@ -763,7 +763,8 @@ def _cache_logic(key, execute_func): cache[key] = cache.pop(key) return result cache[key] = (newres, [f(None) for f in funcs]) - if len(cache) > maxsize: cache.popitem() + # remove the oldest item when cache overflows + if len(cache) > maxsize: del cache[next(iter(cache))] return newres @wraps(func) diff --git a/nbs/03_xtras.ipynb b/nbs/03_xtras.ipynb index c422e1e2..f90ea594 100644 --- a/nbs/03_xtras.ipynb +++ b/nbs/03_xtras.ipynb @@ -154,7 +154,7 @@ "(#5) ['./fastcore/docments.py','./fastcore/dispatch.py','./fastcore/basics.py','./fastcore/docscrape.py','./fastcore/script.py']" ] }, - "execution_count": null, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -259,7 +259,7 @@ "'jpeg'" ] }, - "execution_count": null, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -688,10 +688,10 @@ { "data": { "text/plain": [ - "'pip 23.3.1 from /Users/jhoward/miniconda3/lib/python3.11/site-packages/pip (python 3.11)'" + "'pip 25.0.1 from /Users/drg/.venv/lib/python3.12/site-packages/pip (python 3.12)'" ] }, - "execution_count": null, + "execution_count": 36, "metadata": {}, "output_type": "execute_result" } @@ -1194,10 +1194,10 @@ { "data": { "text/plain": [ - "Path('/Users/daniel.roy.greenfeld/fh/fastcore/fastcore')" + "Path('/Users/drg/git/fastcore/fastcore')" ] }, - "execution_count": null, + "execution_count": 64, "metadata": {}, "output_type": "execute_result" } @@ -1218,7 +1218,7 @@ "Path('../fastcore')" ] }, - "execution_count": null, + "execution_count": 65, "metadata": {}, "output_type": "execute_result" } @@ -1261,10 +1261,10 @@ { "data": { "text/plain": [ - "Path('000_tour.ipynb')" + "Path('llms.txt')" ] }, - "execution_count": null, + "execution_count": 67, "metadata": {}, "output_type": "execute_result" } @@ -1298,7 +1298,7 @@ "(Path('../fastcore/shutil.py'), Path('000_tour.ipynb'))" ] }, - "execution_count": null, + "execution_count": 68, "metadata": {}, "output_type": "execute_result" } @@ -1440,7 +1440,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L389){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L390){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### ReindexCollection\n", "\n", @@ -1451,7 +1451,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L389){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L390){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### ReindexCollection\n", "\n", @@ -1460,7 +1460,7 @@ "*Reindexes collection `coll` with indices `idxs` and optional LRU cache of size `cache`*" ] }, - "execution_count": null, + "execution_count": 75, "metadata": {}, "output_type": "execute_result" } @@ -1496,7 +1496,7 @@ "['e', 'd', 'c', 'b', 'a']" ] }, - "execution_count": null, + "execution_count": 76, "metadata": {}, "output_type": "execute_result" } @@ -1523,7 +1523,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L400){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L401){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "###### ReindexCollection.reindex\n", "\n", @@ -1534,7 +1534,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L400){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L401){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "###### ReindexCollection.reindex\n", "\n", @@ -1543,7 +1543,7 @@ "*Replace `self.idxs` with idxs*" ] }, - "execution_count": null, + "execution_count": 77, "metadata": {}, "output_type": "execute_result" } @@ -1563,7 +1563,7 @@ "['e', 'd', 'c', 'b', 'a']" ] }, - "execution_count": null, + "execution_count": 78, "metadata": {}, "output_type": "execute_result" } @@ -1592,7 +1592,7 @@ "CacheInfo(hits=1, misses=1, maxsize=2, currsize=1)" ] }, - "execution_count": null, + "execution_count": 79, "metadata": {}, "output_type": "execute_result" } @@ -1623,7 +1623,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L404){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L405){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "##### ReindexCollection.cache_clear\n", "\n", @@ -1634,7 +1634,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L404){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L405){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "##### ReindexCollection.cache_clear\n", "\n", @@ -1643,7 +1643,7 @@ "*Clear LRU cache*" ] }, - "execution_count": null, + "execution_count": 80, "metadata": {}, "output_type": "execute_result" } @@ -1663,7 +1663,7 @@ "CacheInfo(hits=0, misses=0, maxsize=2, currsize=0)" ] }, - "execution_count": null, + "execution_count": 81, "metadata": {}, "output_type": "execute_result" } @@ -1688,7 +1688,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L401){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L402){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "##### ReindexCollection.shuffle\n", "\n", @@ -1699,7 +1699,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L401){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L402){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "##### ReindexCollection.shuffle\n", "\n", @@ -1708,7 +1708,7 @@ "*Randomly shuffle indices*" ] }, - "execution_count": null, + "execution_count": 82, "metadata": {}, "output_type": "execute_result" } @@ -1732,10 +1732,10 @@ { "data": { "text/plain": [ - "['a', 'd', 'h', 'c', 'e', 'b', 'f', 'g']" + "['e', 'd', 'b', 'h', 'f', 'c', 'g', 'a']" ] }, - "execution_count": null, + "execution_count": 83, "metadata": {}, "output_type": "execute_result" } @@ -1829,7 +1829,7 @@ "2" ] }, - "execution_count": null, + "execution_count": 87, "metadata": {}, "output_type": "execute_result" } @@ -1988,10 +1988,10 @@ { "data": { "text/plain": [ - "'https://github.com/fastai/fastcore/tree/master/fastcore/test.py#L35'" + "'https://github.com/fastai/fastcore/tree/master/fastcore/test.py#L37'" ] }, - "execution_count": null, + "execution_count": 95, "metadata": {}, "output_type": "execute_result" } @@ -2109,7 +2109,7 @@ "'▂▅▇▇'" ] }, - "execution_count": null, + "execution_count": 102, "metadata": {}, "output_type": "execute_result" } @@ -2291,7 +2291,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L530){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L533){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### EventTimer\n", "\n", @@ -2302,7 +2302,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L530){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L533){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### EventTimer\n", "\n", @@ -2311,7 +2311,7 @@ "*An event timer with history of `store` items of time `span`*" ] }, - "execution_count": null, + "execution_count": 112, "metadata": {}, "output_type": "execute_result" } @@ -2336,8 +2336,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "Num Events: 3, Freq/sec: 205.6\n", - "Most recent: ▁▁▃▁▇ 254.1 263.2 284.5 259.9 315.7\n" + "Num Events: 8, Freq/sec: 361.3\n", + "Most recent: ▃▇▁▁▃ 267.6 322.3 233.1 227.7 269.6\n" ] } ], @@ -2416,7 +2416,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L562){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L565){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### PartialFormatter\n", "\n", @@ -2427,7 +2427,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L562){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L565){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### PartialFormatter\n", "\n", @@ -2436,7 +2436,7 @@ "*A `string.Formatter` that doesn't error on missing fields, and tracks missing fields and unused args*" ] }, - "execution_count": null, + "execution_count": 118, "metadata": {}, "output_type": "execute_result" } @@ -2499,7 +2499,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "2000-01-01 12:00:00 UTC is 2000-01-01 22:00:00+10:00 local time\n" + "2000-01-01 12:00:00 UTC is 2000-01-01 20:00:00+08:00 local time\n" ] } ], @@ -2529,7 +2529,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "2000-01-01 12:00:00 local is 2000-01-01 02:00:00+00:00 UTC time\n" + "2000-01-01 12:00:00 local is 2000-01-01 04:00:00+00:00 UTC time\n" ] } ], @@ -2632,7 +2632,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L619){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L622){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### ContextManagers\n", "\n", @@ -2643,7 +2643,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L619){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L622){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### ContextManagers\n", "\n", @@ -2652,7 +2652,7 @@ "*Wrapper for `contextlib.ExitStack` which enters a collection of context managers*" ] }, - "execution_count": null, + "execution_count": 129, "metadata": {}, "output_type": "execute_result" } @@ -2733,7 +2733,7 @@ "" ] }, - "execution_count": null, + "execution_count": 133, "metadata": {}, "output_type": "execute_result" } @@ -2847,7 +2847,7 @@ "Person(name='Bob', age=UNSET, city='Unknown')" ] }, - "execution_count": null, + "execution_count": 140, "metadata": {}, "output_type": "execute_result" } @@ -2898,7 +2898,7 @@ "Person(name='Bob', age=UNSET, city='NY')" ] }, - "execution_count": null, + "execution_count": 142, "metadata": {}, "output_type": "execute_result" } @@ -2922,7 +2922,7 @@ "Person(name='Bob', age=UNSET, city='Unknown')" ] }, - "execution_count": null, + "execution_count": 143, "metadata": {}, "output_type": "execute_result" } @@ -2942,7 +2942,7 @@ "Person(name='Bob', age=34, city='Unknown')" ] }, - "execution_count": null, + "execution_count": 144, "metadata": {}, "output_type": "execute_result" } @@ -2987,7 +2987,7 @@ "Person(name='Bob', age=UNSET, city='Unknown')" ] }, - "execution_count": null, + "execution_count": 146, "metadata": {}, "output_type": "execute_result" } @@ -3018,7 +3018,7 @@ "Person(name='Bob', age=UNSET, city='Unknown')" ] }, - "execution_count": null, + "execution_count": 147, "metadata": {}, "output_type": "execute_result" } @@ -3049,7 +3049,7 @@ "True" ] }, - "execution_count": null, + "execution_count": 148, "metadata": {}, "output_type": "execute_result" } @@ -3099,7 +3099,7 @@ "{'name': 'Bob', 'city': 'Unknown'}" ] }, - "execution_count": null, + "execution_count": 150, "metadata": {}, "output_type": "execute_result" } @@ -3187,7 +3187,8 @@ " cache[key] = cache.pop(key)\n", " return result\n", " cache[key] = (newres, [f(None) for f in funcs])\n", - " if len(cache) > maxsize: cache.popitem()\n", + " # remove the oldest item when cache overflows\n", + " if len(cache) > maxsize: del cache[next(iter(cache))]\n", " return newres\n", "\n", " @wraps(func)\n", @@ -3250,7 +3251,7 @@ "3" ] }, - "execution_count": null, + "execution_count": 158, "metadata": {}, "output_type": "execute_result" } @@ -3273,7 +3274,7 @@ "3" ] }, - "execution_count": null, + "execution_count": 159, "metadata": {}, "output_type": "execute_result" } @@ -3298,6 +3299,32 @@ " return flexicache(time_policy(seconds), maxsize=maxsize)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# demonstrate that flexicache is LRU\n", + "@flexicache(maxsize=2)\n", + "def cached_func(x): return time()\n", + "\n", + "time_1 = cached_func(1)\n", + "test_eq(time_1, cached_func(1))\n", + "\n", + "time_2 = cached_func(2)\n", + "test_eq(time_1, cached_func(1))\n", + "test_eq(time_2, cached_func(2))\n", + "\n", + "time_3 = cached_func(3) # Removes 1\n", + "\n", + "test_eq(time_2, cached_func(2)) # cache remains\n", + "test_eq(time_3, cached_func(3)) # cache remains\n", + "test_ne(time_1, cached_func(1)) # NEQ, removes 2\n", + "test_ne(time_2, cached_func(2)) # NEQ, removes 3\n", + "test_eq(cached_func(1), cached_func(1))" + ] + }, { "cell_type": "markdown", "metadata": {}, From 3b137ba73f7c64ee7c8ec3c90ec9bb9e1417d7e2 Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Sun, 4 May 2025 18:40:33 +0800 Subject: [PATCH 2/2] Use OrderedDict for FIFO for LRU --- fastcore/xtras.py | 6 +-- nbs/03_xtras.ipynb | 113 +++++++++++++++++++++------------------------ 2 files changed, 56 insertions(+), 63 deletions(-) diff --git a/fastcore/xtras.py b/fastcore/xtras.py index 512cbf97..28632d18 100644 --- a/fastcore/xtras.py +++ b/fastcore/xtras.py @@ -748,8 +748,9 @@ def is_namedtuple(cls): def flexicache(*funcs, maxsize=128): "Like `lru_cache`, but customisable with policy `funcs`" import asyncio + from collections import OrderedDict def _f(func): - cache,states = {}, [None]*len(funcs) + cache,states = OrderedDict(), [None]*len(funcs) def _cache_logic(key, execute_func): if key in cache: result,states = cache[key] @@ -763,8 +764,7 @@ def _cache_logic(key, execute_func): cache[key] = cache.pop(key) return result cache[key] = (newres, [f(None) for f in funcs]) - # remove the oldest item when cache overflows - if len(cache) > maxsize: del cache[next(iter(cache))] + if len(cache) > maxsize: cache.popitem(last=False) return newres @wraps(func) diff --git a/nbs/03_xtras.ipynb b/nbs/03_xtras.ipynb index f90ea594..e1ce4502 100644 --- a/nbs/03_xtras.ipynb +++ b/nbs/03_xtras.ipynb @@ -154,7 +154,7 @@ "(#5) ['./fastcore/docments.py','./fastcore/dispatch.py','./fastcore/basics.py','./fastcore/docscrape.py','./fastcore/script.py']" ] }, - "execution_count": 7, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -259,7 +259,7 @@ "'jpeg'" ] }, - "execution_count": 12, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -691,7 +691,7 @@ "'pip 25.0.1 from /Users/drg/.venv/lib/python3.12/site-packages/pip (python 3.12)'" ] }, - "execution_count": 36, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1197,7 +1197,7 @@ "Path('/Users/drg/git/fastcore/fastcore')" ] }, - "execution_count": 64, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1218,7 +1218,7 @@ "Path('../fastcore')" ] }, - "execution_count": 65, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1264,7 +1264,7 @@ "Path('llms.txt')" ] }, - "execution_count": 67, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1298,7 +1298,7 @@ "(Path('../fastcore/shutil.py'), Path('000_tour.ipynb'))" ] }, - "execution_count": 68, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1440,7 +1440,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L390){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L391){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### ReindexCollection\n", "\n", @@ -1451,7 +1451,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L390){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L391){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### ReindexCollection\n", "\n", @@ -1460,7 +1460,7 @@ "*Reindexes collection `coll` with indices `idxs` and optional LRU cache of size `cache`*" ] }, - "execution_count": 75, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1496,7 +1496,7 @@ "['e', 'd', 'c', 'b', 'a']" ] }, - "execution_count": 76, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1523,7 +1523,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L401){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L402){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "###### ReindexCollection.reindex\n", "\n", @@ -1534,7 +1534,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L401){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L402){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "###### ReindexCollection.reindex\n", "\n", @@ -1543,7 +1543,7 @@ "*Replace `self.idxs` with idxs*" ] }, - "execution_count": 77, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1563,7 +1563,7 @@ "['e', 'd', 'c', 'b', 'a']" ] }, - "execution_count": 78, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1592,7 +1592,7 @@ "CacheInfo(hits=1, misses=1, maxsize=2, currsize=1)" ] }, - "execution_count": 79, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1623,7 +1623,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L405){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L406){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "##### ReindexCollection.cache_clear\n", "\n", @@ -1634,7 +1634,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L405){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L406){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "##### ReindexCollection.cache_clear\n", "\n", @@ -1643,7 +1643,7 @@ "*Clear LRU cache*" ] }, - "execution_count": 80, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1663,7 +1663,7 @@ "CacheInfo(hits=0, misses=0, maxsize=2, currsize=0)" ] }, - "execution_count": 81, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1688,7 +1688,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L402){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L403){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "##### ReindexCollection.shuffle\n", "\n", @@ -1699,7 +1699,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L402){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L403){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "##### ReindexCollection.shuffle\n", "\n", @@ -1708,7 +1708,7 @@ "*Randomly shuffle indices*" ] }, - "execution_count": 82, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1732,10 +1732,10 @@ { "data": { "text/plain": [ - "['e', 'd', 'b', 'h', 'f', 'c', 'g', 'a']" + "['a', 'd', 'g', 'f', 'h', 'e', 'b', 'c']" ] }, - "execution_count": 83, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1829,7 +1829,7 @@ "2" ] }, - "execution_count": 87, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -1991,7 +1991,7 @@ "'https://github.com/fastai/fastcore/tree/master/fastcore/test.py#L37'" ] }, - "execution_count": 95, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -2109,7 +2109,7 @@ "'▂▅▇▇'" ] }, - "execution_count": 102, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -2291,7 +2291,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L533){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L534){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### EventTimer\n", "\n", @@ -2302,7 +2302,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L533){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L534){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### EventTimer\n", "\n", @@ -2311,7 +2311,7 @@ "*An event timer with history of `store` items of time `span`*" ] }, - "execution_count": 112, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -2336,8 +2336,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "Num Events: 8, Freq/sec: 361.3\n", - "Most recent: ▃▇▁▁▃ 267.6 322.3 233.1 227.7 269.6\n" + "Num Events: 1, Freq/sec: 155.1\n", + "Most recent: ▇▂▂▁▁ 386.7 269.9 285.5 249.6 220.0\n" ] } ], @@ -2416,7 +2416,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L565){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L566){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### PartialFormatter\n", "\n", @@ -2427,7 +2427,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L565){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L566){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### PartialFormatter\n", "\n", @@ -2436,7 +2436,7 @@ "*A `string.Formatter` that doesn't error on missing fields, and tracks missing fields and unused args*" ] }, - "execution_count": 118, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -2632,7 +2632,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L622){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L623){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### ContextManagers\n", "\n", @@ -2643,7 +2643,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L622){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L623){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "#### ContextManagers\n", "\n", @@ -2652,7 +2652,7 @@ "*Wrapper for `contextlib.ExitStack` which enters a collection of context managers*" ] }, - "execution_count": 129, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -2733,7 +2733,7 @@ "" ] }, - "execution_count": 133, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -2847,7 +2847,7 @@ "Person(name='Bob', age=UNSET, city='Unknown')" ] }, - "execution_count": 140, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -2898,7 +2898,7 @@ "Person(name='Bob', age=UNSET, city='NY')" ] }, - "execution_count": 142, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -2922,7 +2922,7 @@ "Person(name='Bob', age=UNSET, city='Unknown')" ] }, - "execution_count": 143, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -2942,7 +2942,7 @@ "Person(name='Bob', age=34, city='Unknown')" ] }, - "execution_count": 144, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -2987,7 +2987,7 @@ "Person(name='Bob', age=UNSET, city='Unknown')" ] }, - "execution_count": 146, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -3018,7 +3018,7 @@ "Person(name='Bob', age=UNSET, city='Unknown')" ] }, - "execution_count": 147, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -3049,7 +3049,7 @@ "True" ] }, - "execution_count": 148, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -3099,7 +3099,7 @@ "{'name': 'Bob', 'city': 'Unknown'}" ] }, - "execution_count": 150, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -3172,8 +3172,9 @@ "def flexicache(*funcs, maxsize=128):\n", " \"Like `lru_cache`, but customisable with policy `funcs`\"\n", " import asyncio\n", + " from collections import OrderedDict\n", " def _f(func):\n", - " cache,states = {}, [None]*len(funcs)\n", + " cache,states = OrderedDict(), [None]*len(funcs)\n", " def _cache_logic(key, execute_func):\n", " if key in cache:\n", " result,states = cache[key]\n", @@ -3187,8 +3188,7 @@ " cache[key] = cache.pop(key)\n", " return result\n", " cache[key] = (newres, [f(None) for f in funcs])\n", - " # remove the oldest item when cache overflows\n", - " if len(cache) > maxsize: del cache[next(iter(cache))]\n", + " if len(cache) > maxsize: cache.popitem(last=False)\n", " return newres\n", "\n", " @wraps(func)\n", @@ -3251,7 +3251,7 @@ "3" ] }, - "execution_count": 158, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -3274,7 +3274,7 @@ "3" ] }, - "execution_count": 159, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -3382,13 +3382,6 @@ "#|hide\n", "import nbdev; nbdev.nbdev_export()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": {