From 5cdec57926f0c2022329908ce9a74b775ec19841 Mon Sep 17 00:00:00 2001
From: Andreas Kloeckner <inform@tiker.net>
Date: Sat, 21 Jun 2014 19:02:50 -0500
Subject: [PATCH] Add memoize_on_first_arg

---
 pytools/__init__.py | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/pytools/__init__.py b/pytools/__init__.py
index 6cd3205..8bf62b7 100644
--- a/pytools/__init__.py
+++ b/pytools/__init__.py
@@ -480,6 +480,47 @@ def memoize_method(method):
     return new_wrapper
 
 
+def memoize_on_first_arg(function):
+    """Like :func:`memoize_method`, but for functions that take the object
+    to do memoization as first argument.
+
+    Supports cache deletion via ``function_name.clear_cache(self)``.
+
+    .. note::
+        *clear_cache* support requires Python 2.5 or newer.
+    """
+
+    cache_dict_name = intern("_memoize_dic_"
+            + function.__module__ + function.__name__)
+
+    def wrapper(obj, *args, **kwargs):
+        if kwargs:
+            key = (_HasKwargs, frozenset(kwargs.iteritems())) + args
+        else:
+            key = args
+
+        try:
+            return getattr(obj, cache_dict_name)[key]
+        except AttributeError:
+            result = function(obj, *args, **kwargs)
+            setattr(obj, cache_dict_name, {key: result})
+            return result
+        except KeyError:
+            result = function(obj, *args, **kwargs)
+            getattr(obj, cache_dict_name)[key] = result
+            return result
+
+    def clear_cache(obj):
+        delattr(obj, cache_dict_name)
+
+    if sys.version_info >= (2, 5):
+        from functools import update_wrapper
+        new_wrapper = update_wrapper(wrapper, function)
+        new_wrapper.clear_cache = clear_cache
+
+    return new_wrapper
+
+
 def memoize_method_with_uncached(uncached_args=[], uncached_kwargs=set()):
     """Supports cache deletion via ``method_name.clear_cache(self)``.
 
-- 
GitLab