From a16bc50a4ff27058763117c7f022da99863b2f7d Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauld.mccarthy@gmail.com> Date: Tue, 16 Aug 2016 11:51:17 +0100 Subject: [PATCH] Re-worked memoize function so it can be instanceified. Image.isNeurological is now memoized. --- fsl/data/image.py | 5 ++-- fsl/utils/memoize.py | 58 +++++++++++++++++--------------------------- 2 files changed, 25 insertions(+), 38 deletions(-) diff --git a/fsl/data/image.py b/fsl/data/image.py index 88906cdc2..a4e210b67 100644 --- a/fsl/data/image.py +++ b/fsl/data/image.py @@ -242,7 +242,7 @@ class Nifti1(object): # a 4x4 array (via memoizeMD5), or the call # to aff2axcodes. I'm guessing the latter, # but am not 100% sure. - @memoize.memoizeMD5 + @memoize.Instanceify(memoize.memoizeMD5) def axisMapping(self, xform): """Returns the (approximate) correspondence of each axis in the source coordinate system to the axes in the destination coordinate system, @@ -257,10 +257,11 @@ class Nifti1(object): return nib.orientations.aff2axcodes(xform, inaxes) + @memoize.Instanceify(memoize.memoize) def isNeurological(self): """Returns ``True`` if it looks like this ``Nifti1`` object is in neurological orientation, ``False`` otherwise. This test is purely - based on the determinent of the voxel-to-mm transformation matrix - + based on the determinant of the voxel-to-mm transformation matrix - if it has a positive determinant, the image is assumed to be in neurological orientation, otherwise it is assumed to be in radiological orientation. diff --git a/fsl/utils/memoize.py b/fsl/utils/memoize.py index cffb5e4ad..0a51b446e 100644 --- a/fsl/utils/memoize.py +++ b/fsl/utils/memoize.py @@ -27,7 +27,7 @@ log = logging.getLogger(__name__) # TODO Make this a class, and add # a "clearCache" method to it. -def memoize(args=None, kwargs=None): +def memoize(func): """Memoize the given function by the value of the input arguments, allowing the caller to specify which positional arguments (by index) and keyword arguments (by name) are used for the comparison. @@ -36,55 +36,41 @@ def memoize(args=None, kwargs=None): memoized on all arguments. Note that the arguments used for memoization must be hashable, as they are used as keys in a dictionary. - This decorator must always be called with brackets, e.g. :: - - memoize() - def myfunc(): - # do stuff to be memoized - :arg args: A list of positional argument indices. :arg kwargs: A list of keyword argument names. """ - def decorator(func): - - cache = {} - - def wrapper(*a, **kwa): - - key = [] + cache = {} + defaultKey = '_memoize_noargs_' - if args is not None: key += [a[ i] for i in args] - if kwargs is not None: key += [kwa[k] for k in kwargs] + def wrapper(*a, **kwa): - # This decorator was created without - # any arguments specified - use all - # the arguments as the cache key. - if len(key) == 0: + key = [] - # Keyword arguments are unordered, - # so we'll try and overcome this - # by sorting the kwarg dict keys. - key = list(a) + list([kwa[k] for k in sorted(kwa.keys)]) + if a is not None: key += list(a) + if kwa is not None: key += [kwa[k] for k in sorted(kwa.keys())] - key = tuple(key) + # This decorator was created without + # any arguments specified - use the + # default cache key. + if len(key) == 0: + key = [defaultKey] - try: - result = cache[key] + key = tuple(key) + + try: + result = cache[key] - except KeyError: + except KeyError: - result = func(*a, **kwa) - cache[key] = result + result = func(*a, **kwa) + cache[key] = result - log.debug('Adding to cache[{}]: {}'.format( - key, result)) + log.debug('Adding to cache[{}]: {}'.format(key, result)) - return result - return wrapper - - return decorator + return result + return wrapper def memoizeMD5(func): -- GitLab