Created
May 27, 2020 11:07
-
-
Save basnijholt/3ef0c32abaabd5799673f377a727dae3 to your computer and use it in GitHub Desktop.
Dynamically cache a method of an object once
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import functools | |
import random | |
import time | |
import types | |
class A: | |
def f(self): | |
time.sleep(1) | |
return random.random() | |
def cache_once(obj): | |
"""Caches a method once.""" | |
cache = {} | |
done = set([]) # args which already have been cached | |
@functools.wraps(obj) | |
def memoizer(*args, **kwargs): | |
self, *args = args | |
key = str(args) + str(kwargs) | |
if key in cache and key not in done: | |
# this is the only time we return a cached result | |
done.add(key) | |
return cache.pop(key) | |
else: | |
cache[key] = obj(*args, **kwargs) | |
return cache[key] | |
memoizer._cache = cache | |
memoizer._done = done | |
return memoizer | |
a = A() | |
a.f = types.MethodType(cache_once(a.f), a) | |
a.f() # takes 1s | |
a.f() # is cached | |
a.f() # takes 1s | |
a.f() # takes 1s |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment