具有修饰函数的任意位置参数的Python修饰器

2024-04-19 18:26:40 发布

您现在位置:Python中文网/ 问答频道 /正文

python decorator变成“多态”的方式是什么?我的意思是它寻找修饰函数的一个精确参数,对它做些什么,然后将修改后的参数传递给函数。但是,这个具有公共名称的参数在任何修饰函数中都有任意位置。你知道吗

def decorator(func):
    def wrapper(exactly_this_param, *args):
        new = do_smth(exactly_this_param)
        return func(exactly_this_param=new, *args)
    return wrapper

@decorator
def func1(a, b, exactly_this_param, c):
    # does something

@decorator
def func2(exactly_this_param):
    # does something

@decorator
def func3(a, b, c, d, e, exactly_this_param, *args, **kwargs):
    # does something

Tags: 函数new参数returnparamdefargsdecorator
1条回答
网友
1楼 · 发布于 2024-04-19 18:26:40

对于关键字参数(kwargs),这将很容易,因为*kwargs在decorator中为您提供关键字参数的名称和值。 所以你会收到这样的信息:

func3(1,2,3,4,5,6,7,test="hallo")

会给你:

kwargs{'test': 'hallo'}

所以你可以搜索“正好是这个参数”然后改变它。。你知道吗

但你选择使用普通参数。这是一个步骤,但也是可能的。你知道吗

所以这里有一个可能的解决方案:(我使用了python3)

对于“非关键字参数”(args),可以使用以下组合:

  • args->;提供此func调用的实际值的元组
  • func.代码.co\u varnames->;提供函数定义中的参数名称

我把它们分配给变量函数参数

func_params = func.__code__.co_varnames

因此,您可以在func.code..co\u varnames中查找的索引“exactly\u this\u param”,并更改args中正好位于该索引的值。这是这个街区:

new_args[func_params.index("exactly_this_param")]=999

您还必须将args转换为一个列表(new\u args),然后再转换回一个元组,因为元组在python中是不可变的。你知道吗

这会产生如下结果(示例代码-但正在运行):

def decorator(func):
def wrapped(*args, **kwargs):
    # a tuple of the names of the parameters that func accepts
    print("    ... decorator magic ....")
    print("    .... args" + str(args))
    print("    .... kwargs" + str(kwargs))
    func_params = func.__code__.co_varnames
    print("    .... param_names:" + str(func_params))
    # grab all of the kwargs that are not accepted by func
    new_args=list(args)
    new_args[func_params.index("exactly_this_param")]=999
    args=tuple(new_args)
    print("    .... new_args" + str(args))
    return func(*args, **kwargs)
return wrapped

@decorator
def func1(a, b, exactly_this_param, c):
    # does something
    print("func1 => exactly_this_slightly_different_param: " + str(exactly_this_param))

@decorator
def func2(exactly_this_param):
    # does something
    print("func2 =>  exactly_this_slightly_different_param: " + str(exactly_this_param))

@decorator
def func3(a, b, c, d, e, exactly_this_param, *args, **kwargs):
    # does something
    print("func3 =>  exactly_this_slightly_different_param: " + str(exactly_this_param))

if __name__ == "__main__":
    func1(1,2,3,4)
    func2(12)
    func3(1,2,3,4,5,6,7,test="hallo")

结果输出显示,始终找到参数并将其更改为999。你知道吗

c:\khz\devel>python test_dec.py
    ... decorator magic ....
    .... args(1, 2, 3, 4)
    .... kwargs{}
    .... param_names:('a', 'b', 'exactly_this_param', 'c')
    .... new_args(1, 2, 999, 4)
func1 => exactly_this_slightly_different_param: 999
    ... decorator magic ....
    .... args(12,)
    .... kwargs{}
    .... param_names:('exactly_this_param',)
    .... new_args(999,)
func2 =>  exactly_this_slightly_different_param: 999
    ... decorator magic ....
    .... args(1, 2, 3, 4, 5, 6, 7)
    .... kwargs{'test': 'hallo'}
    .... param_names:('a', 'b', 'c', 'd', 'e', 'exactly_this_param', 'args', 'kwargs')
    .... new_args(1, 2, 3, 4, 5, 999, 7)
func3 =>  exactly_this_slightly_different_param: 999

基于this SO question的答案。你知道吗

相关问题 更多 >