返回一个函数的Python装饰器,该函数替换了一个或多个参数 [英] Python decorator that returns a function with one or more arguments replaced

查看:116
本文介绍了返回一个函数的Python装饰器,该函数替换了一个或多个参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想为一组函数创建一个装饰器,以替换函数的一个或多个参数。我想到的第一个想法是创建一个装饰器,该装饰器返回带有替换参数的部分函数。
我对装饰函数的调用方式不满意,但是即使被正确调用,我也会遇到TypeError。

I would like to create a decorator to a set of functions that replaces one or more of the arguments of the functions. The first thought that came to my mind was to create a decorator that returns a partial of the function with the replaced arguments. I'm unhappy with the way the decorated function is called, but even when it's being called "properly", i get a TypeError.

这里是一些示例代码:

def decor(func, *args, **kwargs):
    def _new_func(*args, **kwargs):
        return partial(func, *args, **kwargs, v=100)
    return _new_func

@decor
def some_function(a, v, c):
    return a, v, c

some_function(1,2,3)  # functools.partial(<function some_function at 0x7f89a8bed8c8>, 1, 2, 3, v=100)
some_function(1,2,3)(1,2,3)  # TypeError: some_function() got multiple values for argument 'v'

我敢肯定,有一种简单的方法可以创建一个装饰器来替换某些参数,但是还没有弄清楚。

I'm sure there is an easy way to create a decorator that replaces some of the arguments, but haven't figured it out yet.

推荐答案

您必须返回不完整部分作为装饰结果:

You'd have to return the partial as the decoration result:

def decor(func):
    return partial(func, v=100)

但是,此总是设置 v = 100 ,即使您按位置传递了 v 的另一个值。您仍然会有同样的问题。

However, this always sets v=100, even if you passed in another value for v by position. You'd still have the same issue.

您需要创建一个装饰器,该装饰器知道什么位置参数 v 是,并在其中找到作为关键字参数:

You'd need to create a decorator that knows what positional argument v is, and look for it there and as a keyword argument:

from inspect import getargspec

def decor(func):
    vpos = getargspec(func).args.index('v')
    def wrapper(*args, **kwargs):
        if len(args) > vpos:
            args = list(args)
            args[vpos] = 100
        else:
            kwargs['v'] = 100
        return func(*args, **kwargs)        
    return wrapper

上述装饰器将设置 v 参数始终设为100, 。如果您尝试将 v 设置为位置参数或关键字参数,最终无论如何将其设置为100:

The above decorator will set the v argument to 100, always. Wether you tried to set v as a positional argument or as a keyword argument, in the end it'll be set to 100 anyway:

>>> @decor
... def some_function(a, v, c):
...     return a, v, c
...
>>> some_function(1, 2, 3)
(1, 100, 3)
>>> some_function(1, v=2, c=3)
(1, 100, 3)

如果只想为 v 提供默认参数(如果未明确设置),则必须反转测试:

If you only wanted to provide a default argument for v if it wasn't explicitly set, you'd have to invert the tests:

def decor(func):
    vpos = getargspec(func).args.index('v')
    def wrapper(*args, **kwargs):
        if len(args) <= vpos and 'v' not in kwargs:
            kwargs['v'] = 100
        return func(*args, **kwargs)        
    return wrapper

此时 v 仅在尚未设置的情况下提供:

at which point v is only provided if not already set:

>>> @decor
... def some_function(a, v, c):
...     return a, v, c
...
>>> some_function(1, c=3)  # v not set
(1, 100, 3)
>>> some_function(1, 2, c=3)  # v is set
(1, 2, 3)
>>> some_function(1, v=2, c=3)  # v is set as keyword argument
(1, 2, 3)

这篇关于返回一个函数的Python装饰器,该函数替换了一个或多个参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆