Skip to content

Instantly share code, notes, and snippets.

@terrycojones
Created August 11, 2011 19:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save terrycojones/1140581 to your computer and use it in GitHub Desktop.
Save terrycojones/1140581 to your computer and use it in GitHub Desktop.
deferred memoizer
from twisted.internet import defer, fail, succeed
from twisted.python import failure
class DeferredMemoizer(object):
def __init__(self, func):
self._func = func
self._pool = {}
self._results = {}
def _callOthers(self, result, key):
self._results[key] = result
if isinstance(result, failure.Failure):
for d in self._pool[key]:
d.errback(result)
else:
for d in self._pool[key]:
d.callback(result)
del self._pool[key]
return result
def _call(self, instance, *args, **kwargs):
key = (args, hash(tuple(sorted(kwargs.items()))))
try:
result = self._results[key]
except KeyError:
# We don't yet have a result, do we have a deferred outstanding?
if key in self._pool:
d = defer.Deferred()
self._pool[key].append(d)
return d
else:
d = self._func(instance, *args, **kwargs)
if isinstance(d, defer.Deferred):
self._pool[key] = []
self._returnsDeferred = True
d.addBoth(self._callOthers, key)
return d
else:
self._returnsDeferred = False
self._results[key] = d
return d
else:
# We already have a result.
if self._returnsDeferred:
if isinstance(result, failure.Failure):
return fail(result)
else:
return succeed(result)
else:
return result
def __get__(self, instance, owner):
def wrapper(*args, **kwargs):
return self._call(instance, *args, **kwargs)
return wrapper
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment