简体   繁体   English

应用'setattr'后如何捕获原始function的arguments?

[英]How to capture arguments of original function after applying 'setattr' to it?

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.要添加此自定义逻辑,我使用内置 python function setattr。

Also, people of the same project want to capture arguments for some of the functions that are in the same list.此外,同一项目的人希望为同一列表中的某些功能捕获 arguments。 To capture arguments they use inspect.getcallargs function.为了捕获 arguments,他们使用了 inspect.getcallargs function。 However, instead of getting arguments of original function they get the arguments of the wrapper function.但是,他们没有得到原始 function 的 arguments,而是得到了包装器 ZC1C425268E17385D1AB5044 的 arguments。

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:因此,在 function 中遍历要装饰的函数列表,我有如下所示的内容:

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:如果假设原始 function 如下所示:

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} 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:你将需要两件事 - 首先是你的装饰器本身是用functools.wraps()装饰的,因此装饰的 function 上的一些元数据被添加到装饰的 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.但是,不要让inspect.getcallargs反映装饰的签名。 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 :取而代之的是,您必须使用inspect.signature - 它返回一个更丰富的Signature object,但它有一个看起来像从.getcallargs返回的.parameters属性:


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">})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM