Python 2.7:检查是否使用装饰器传递了默认参数

时间:2017-11-16 16:20:25

标签: python python-2.7

我正在寻找一些我不确定如何表现并且无法找到答案的东西。

假设我有一个除arg2之外的参数数量未知的函数。此外,arg2没有固定的参数位置:

def some_func(arg1, arg2=None, maybe_arg3=None, maybe_not_arg4=None):
    # Do some stuff

现在我想检查用户是否已经传递arg2并将其替换为装饰器,例如:

def some_dec(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        # Do some stuff
        # check if arg2 is passed and replace
        rv = func(*args, **kwargs)
        return rv
    return wrapper

如果它作为键/值传递,那么从kwargs获取它是没有问题但是如果它传递给args我怎么得到它? (因为IDK函数需要的参数数量)

2 个答案:

答案 0 :(得分:1)

你可以先查看kwargs dict的参数,如果缺少,它可能会成为args中的第二个参数;检查args是否包含两个以上的参数,并且:

def some_dec(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        if 'args2' in kwargs:
             kwargs['args2'] = 'new value' # update value
        elif len(args) > 1:
             args = (args[0], 'new value') + args[2:] # rebuild args with new value
        rv = func(*args, **kwargs)
        return rv
    return wrapper

答案 1 :(得分:1)

inspect.signature应该给你你想要的东西:

def f(x, y, z, a=4):
    pass

import inspect
s = inspect.signature(f)

b = s.bind_partial(2, 4, 6, 8)
'a' in b.arguments

-> True

b = s.bind_partial(2, 4, 6)
'a' in b.arguments

-> False

请注意,这是在Python 3.3版本中引入的。在旧版本inspect.getargspec上提供了一些相同的功能。

所以你的装饰师看起来像:

import inspect
import functools

def nag_a(func):
    sig = inspect.signature(func)
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        if not 'a' in sig.bind_partial(*args, **kwargs).arguments:
            print("You really should pass 'a', y'know.")
        rv = func(*args, **kwargs)
        return rv
    return wrapper

def nag_a_27(func):
    spec = inspect.getargspec(func)
    psn = spec.args.index('a')
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        if not 'a' in kwargs and len(args) <= psn:
            print "You really should pass 'a', y'know."
        rv = func(*args, **kwargs)
        return rv
    return wrapper

@nag_a
def f(x, y, a=None):
    pass