I'm currently writing and learning about decorators (with and without arguments). Here is an example of a decorator with one argument that redirects the output of a function to a log file. The code works, but my questions are the following:
Thank you in advance!
def redirect_output(log_file):
"""
Decorator to redirect the stdout written output of a function to a specified
log file.
Args:
log_file (str): The path to the log file where the output will be redirected.
"""
def redirect_output_decorator(func):
@functools.wraps(func)
def redirect_output_wrapper(*args, **kwargs) -> Any:
output = StringIO()
with redirect_stdout(output):
func(*args, **kwargs)
output_lines = output.getvalue().splitlines()
if output_lines:
file_logger("Output from {}: ".format(func.__name__), log_file)
for line in output_lines:
file_logger(line, log_file, with_date=False)
return redirect_output_wrapper
return redirect_output_decorator
ParamSpec
is a solution to this problem.
Here is the code example
in its document.
from typing import TypeVar, ParamSpec
import logging
T = TypeVar('T')
P = ParamSpec('P')
def add_logging(f: Callable[P, T]) -> Callable[P, T]:
'''A type-safe decorator to add logging to a function.'''
def inner(*args: P.args, **kwargs: P.kwargs) -> T:
logging.info(f'{f.__name__} was called')
return f(*args, **kwargs)
return inner
It is officially supported after Python 3.10, but is also supported by importing from typing_extensions
(https://github.com/python/typing_extensions) for python version greater than 3.7