Imagine this made-up decorator that tries to capture the arguments of the wrapped function and save them to some key-value store for logging purposes:
import json
from functools import wraps
some_path = ...
def log_args_to_json(func):
@wraps(func)
def wrapper(*args, **kwargs):
# What to do with the args?
data = json.dumps("func_name": func.__name__, "kwargs": kwargs)
some_path.write_text(data)
return func(*args, **kwargs)
return wrapper
@log_args_to_json
def say_hello(name, suffix):
print(f"Hello, {name}{suffix}")
With the following calls:
say_hello("John", "!") # File has: {}
say_hello("John", suffix="!") # File has {"suffix": "!"}
This decorator doesn’t store the *args
because the destination is a key-value store (I chose a JSON file for simplicity, but this could go anywhere) and it doesn’t know the argument names. It could store it as a list, but that would be much less readable to a person viewing the logs (they wouldn’t know what argument each value corresponds to)
Obviously, the decorator can’t just know the names of the arguments, because they are positional - and would correspond to different names for each function. But python is able to parse the function’s signature and figure out which positional argument corresponds to each value.
I’m wondering if there’s any simple way for me to do this in my code. Maybe I’m missing something incredibly obvious here, but it sucked that I had to make all my arguments keyword only just so I could get the names, when there clearly is a way for Python to figure it out. The only soluiton I could think of is analyzing the names using the function’s __code__
, but that seems like it would be complicated (Again, maybe it’s simple and I’m wrong here).