I have a module in a project that loads before anything else and this module needs to add custom logic to a list of functions that I retrieve from database. To add this custom logic I use builtin python function setattr.
Also, people of the same project want to capture arguments for some of the functions that are in the same list. To capture arguments they use inspect.getcallargs function. However, instead of getting arguments of original function they get the arguments of the wrapper function.
I understand why this happens but don't have a solution for the problem.
My decorator/wrapper looks like the following:
def func_decorator(func, some_other_params):
def func_to_return(*args, **kwargs):
# some code
payload = func(*args, **kwargs)
# some other code
return payload
return func_to_return
So, in the function that goes over the list of functions to decorate I have something that looks like the following:
def add_custom_logic_to_funcs:
....
for func_name in funcs:
func = getattr(func_class, func_name)
setattr(func_class, func_name, func_decorator(func, some_params))
If let's say original function looks like the following:
class A:
def(self, x=None, y=None, z=1):
#some code
Calling inspect.getcallargs results in returnning {'args': (some object at 0x000000001BCA8C50,), 'kwargs': {}} instead of {'self': some object at 0x000000001BCA8C50, 'x': None, 'y': None, 'z': 1}
You will need two things there - First is that your decorator is itself decorated with functools.wraps()
, so that some metadata on the decorated function is added to the decorated function:
from functools import decorator
def func_decorator(func, some_other_params):
@wraps(func)
def func_to_return(*args, **kwargs):
# some code
payload = func(*args, **kwargs)
# some other code
return payload
return func_to_return
That however, don't make inspect.getcallargs
to reflect the decorated signature. Instead of that, you have to use inspect.signature
- which returns a richer Signature
object, but that have a .parameters
attribute that will look like the return from .getcallargs
:
In [26]: def deco(func):
...: @wraps(func)
...: def wrapper(*args, **kw):
...: return func(*args, **kw)
...: return wrapper
...:
In [27]: class A:
...: @deco
...: def b(self, a, b=2):
...: pass
...:
In [28]: inspect.signature(A().b).parameters
Out[28]: mappingproxy({'a': <Parameter "a">, 'b': <Parameter "b=2">})
In [29]: inspect.signature(A.b).parameters
Out[29]:
mappingproxy({'self': <Parameter "self">,
'a': <Parameter "a">,
'b': <Parameter "b=2">})
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.