This is meant to calculate execution time and log / print it:
def timer(logger=None): def decorator(func): def wrapper(*args, **kwargs): start_time = perf_counter() result = func(*args, **kwargs) total_time = perf_counter() - start_time message = f'{func.__name__} Time: ' f'{total_time} seconds' if logger is not None: logger.info(message) else: print(message) return result return wrapper return decorator @timer def decorated(): print("Running ...") if __name__ == '__main__': decorated() I'm expecting this to print time, instead it complains about a missing argument:
TypeError: decorator() missing 1 required positional argument: 'func' However, when I do:
@timer(None) def decorated(): print("Running ...") or:
@timer(logger=None) def decorated(): print("Running ...") It works! what is this nonsense?
Running ... decorated Time: 2.3044999999999316e-05 seconds Notes:
- To those marking my question as a duplicate, can you explain why other decorators work just fine?
- In the example below,
lru_cacheacceptsmaxsizeandtypedparameters and works without explicit calls as well.
Example:
from functools import lru_cache @lru_cache def decorated(): print("Running ...") Out:
Running ...
@timerreturnsdecoratorfunction. On the other hand,@timer()will executetimerfirst then returndecoratorwhich in turn used to decoratedecorated.functools.lru_cache, it works as well as many other decorators without explicit calls()lru_cacheis probably not a parametrizable decorator (however, I did not check), but yourtimerdecorator is parametrizable, this is the key point.