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?
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