I have a decorator that I use to suppress and log exceptions within a function. The code is something like this:
def log_exceptions(func):
def wrapper(*args, **kwargs):
try:
ret = func(*args, **kwargs)
except Exception as e:
print(e)
print(args, kwargs) # also log what arguments caused the exception
return ret
return wrapper
A problem here is that, it is hard to manually match the printed argument values to the argument names of the function, because positional arguments could also go inside kwargs
, and there may be args
and kwargs
arguments in the inner function as well. So, it would be useful to match the args
and kwargs
values in the wrapper with argument names in the inner function.
My question is then, is there a built-in way to do this matching? If not, what would be an elegant way to implement it?
If the signature can be determined, then inspect.signature(func).bind(*args, **kwargs)
does the job.
inspect.signature(func)
(lowercase s) attempts to compute a Signature
object (capital S) representing a callable's signature, and the resulting Signature
's bind
method matches the signature against provided arguments, returning a BoundArguments
object. The arguments
attribute of the resulting object is an ordered mapping of parameter names to values, excluding arguments that fell back on default values.
Here's an example of how you might use it:
import inspect
try:
sig = inspect.signature(func)
except (TypeError, ValueError):
print('Could not determine function signature.')
else:
try:
bound = sig.bind(*args, **kwargs)
except TypeError:
print('Could not bind arguments to function signature.')
print('Signature:', sig)
print('Positional arguments:', args)
print('Keyword arguments:', kwargs)
else:
# You can use bound.apply_defaults() to include defaults
print('Bound arguments (defaults not included):')
for name, value in bound.parameters:
print('{}: {!r}'.format(name, value))