What is memoization and how can I use it in Python?

前端 未结 13 1137
情歌与酒
情歌与酒 2020-11-21 17:25

I just started Python and I\'ve got no idea what memoization is and how to use it. Also, may I have a simplified example?

相关标签:
13条回答
  • 2020-11-21 18:16

    Well I should answer the first part first: what's memoization?

    It's just a method to trade memory for time. Think of Multiplication Table.

    Using mutable object as default value in Python is usually considered bad. But if use it wisely, it can actually be useful to implement a memoization.

    Here's an example adapted from http://docs.python.org/2/faq/design.html#why-are-default-values-shared-between-objects

    Using a mutable dict in the function definition, the intermediate computed results can be cached (e.g. when calculating factorial(10) after calculate factorial(9), we can reuse all the intermediate results)

    def factorial(n, _cache={1:1}):    
        try:            
            return _cache[n]           
        except IndexError:
            _cache[n] = factorial(n-1)*n
            return _cache[n]
    
    0 讨论(0)
  • 2020-11-21 18:17

    I've found this extremely useful

    def memoize(function):
        from functools import wraps
    
        memo = {}
    
        @wraps(function)
        def wrapper(*args):
            if args in memo:
                return memo[args]
            else:
                rv = function(*args)
                memo[args] = rv
                return rv
        return wrapper
    
    
    @memoize
    def fibonacci(n):
        if n < 2: return n
        return fibonacci(n - 1) + fibonacci(n - 2)
    
    fibonacci(25)
    
    0 讨论(0)
  • 2020-11-21 18:17

    Memoization is basically saving the results of past operations done with recursive algorithms in order to reduce the need to traverse the recursion tree if the same calculation is required at a later stage.

    see http://scriptbucket.wordpress.com/2012/12/11/introduction-to-memoization/

    Fibonacci Memoization example in Python:

    fibcache = {}
    def fib(num):
        if num in fibcache:
            return fibcache[num]
        else:
            fibcache[num] = num if num < 2 else fib(num-1) + fib(num-2)
            return fibcache[num]
    
    0 讨论(0)
  • 2020-11-21 18:17

    Just wanted to add to the answers already provided, the Python decorator library has some simple yet useful implementations that can also memoize "unhashable types", unlike functools.lru_cache.

    0 讨论(0)
  • 2020-11-21 18:18

    Solution that works with both positional and keyword arguments independently of order in which keyword args were passed (using inspect.getargspec):

    import inspect
    import functools
    
    def memoize(fn):
        cache = fn.cache = {}
        @functools.wraps(fn)
        def memoizer(*args, **kwargs):
            kwargs.update(dict(zip(inspect.getargspec(fn).args, args)))
            key = tuple(kwargs.get(k, None) for k in inspect.getargspec(fn).args)
            if key not in cache:
                cache[key] = fn(**kwargs)
            return cache[key]
        return memoizer
    

    Similar question: Identifying equivalent varargs function calls for memoization in Python

    0 讨论(0)
  • 2020-11-21 18:22

    Memoization effectively refers to remembering ("memoization" → "memorandum" → to be remembered) results of method calls based on the method inputs and then returning the remembered result rather than computing the result again. You can think of it as a cache for method results. For further details, see page 387 for the definition in Introduction To Algorithms (3e), Cormen et al.

    A simple example for computing factorials using memoization in Python would be something like this:

    factorial_memo = {}
    def factorial(k):
        if k < 2: return 1
        if k not in factorial_memo:
            factorial_memo[k] = k * factorial(k-1)
        return factorial_memo[k]
    

    You can get more complicated and encapsulate the memoization process into a class:

    class Memoize:
        def __init__(self, f):
            self.f = f
            self.memo = {}
        def __call__(self, *args):
            if not args in self.memo:
                self.memo[args] = self.f(*args)
            #Warning: You may wish to do a deepcopy here if returning objects
            return self.memo[args]
    

    Then:

    def factorial(k):
        if k < 2: return 1
        return k * factorial(k - 1)
    
    factorial = Memoize(factorial)
    

    A feature known as "decorators" was added in Python 2.4 which allow you to now simply write the following to accomplish the same thing:

    @Memoize
    def factorial(k):
        if k < 2: return 1
        return k * factorial(k - 1)
    

    The Python Decorator Library has a similar decorator called memoized that is slightly more robust than the Memoize class shown here.

    0 讨论(0)
提交回复
热议问题