Recursions in closures

0
# -*- coding: utf-8 -*-

def memoize(limit, *, message = 'Limit exceded'):
    count = 0
    def inner(func):
        cache = {}
        def wrapped(number):
            nonlocal count
            if count < limit:
                if number not in cache:
                    cache[number] = func(number)
                count += 1
                return cache[number]
            print(message)
        return wrapped
    return inner

@memoize(5)
def fat(x):
    if x < 2:
        return 1
    return x * fat(x - 1)
In theory the algorithm should receive a number that would set a storage limit of the results in a cache, instead of raising an exception I simply show the message that was passed or the default ("Limit exceded") if the limit number in the cache is reached. The problem is that it only runs the program only once and shows the message, but where is the error ???

    
asked by anonymous 05.04.2018 / 15:13

1 answer

2

The code is right (with the only detail that does not make sense to keep the variable count alone in memoize - it should either be within inner , or cache should be out, along with it , but that's aesthetic).

What happens is that your decorated function is itself recursive , that is, a single call to fat will call the decorator wrapper n times: hence it already burst its limit of 5 calls. Increase the call limit, or make the call to fat with a smaller number and you will see that it is.

If you want incoming calls to fat not to the limit, you can put a counter to detect recursion, and do not increase the% of internal% in that case (and there, be careful that things start to get complicated if the program is multi-threaded, this recursion counter has to be a thread-local variable)

def memoize(limit, *, message = 'Limit exceded'):
    def inner(func):
        count = 0
        cache = {}
        recursing = 0
        def wrapped(number):
            nonlocal count, recursing

            if count < limit:
                recursing += 1
                if number not in cache:
                    cache[number] = func(number)
                recursing -= 1
                if not recursing:
                    count += 1
                return cache[number]
            print(message)
        return wrapped
    return inner
    
07.04.2018 / 18:37