Search code examples
python-3.xpython-decorators

Calling a decorated function twice returns only the decorator and not the function


Here is my code that defines the timed decorator:

from functools import wraps, lru_cache

def timed(fn):
    from time import perf_counter

    @wraps(fn)
    def inner(*args,**kwargs):
        start = perf_counter()
        result = fn(*args,**kwargs)
        end = perf_counter()
        timer = end - start

        fs = '{} took {:.3f} microseconds'
        print(fs.format(fn.__name__, (end - start) * 1000000))

        return result
    return inner

Here is the function definition:

@timed
@lru_cache
def factorial(n):
    result = 1
    cache = dict()
    if n < 2:
        print('Calculating factorial for n > 1')

        result = 1
        print(f'factorial of {result} is {result}')

    else:
        for i in range(1,n+1):
            if i in cache.items():
                result = cache[i]
                #print(f'factorial of {i} is {result}')
            else:
                result *= i
                cache[i] = result

        print(f'factorial of {i} is {result}')
            #print(f'{cache}')
    return result

Here are the calls to the functions:

factorial(3)

factorial(10)

factorial(10)

Here is the output

factorial of 3 is 6
factorial took 32.968 microseconds
factorial of 10 is 3628800
factorial took 11.371 microseconds
**factorial took 0.323 microseconds**

Question: Why when I call factorial(10) the second time, there is no Print out?


Solution

  • You only want to cache pure functions; your factorial isn't pure, because it has a side effect of writing to standard output.

    For the behavior you want, define two functions: a pure function that you cache, and an impure wrapper that uses the pure function.

    @lru_cache
    def factorial_math(n):
        result = 1
        for i in range(2, n):
            result *= i
        return result
    
    @timed
    def factorial(n):
        result = factorial_math(n)
        print(f'factorial of {n} is {result}')
        return result