在不修改函数定义的情况下调用带可选参数的函数

0 投票
2 回答
1016 浏览
提问于 2025-04-15 18:57

我想知道怎么调用一个函数,并传递一个它可能不会期待的参数。

几天前我遇到了这个问题,找到了一个解决办法。但今天我决定看看我想做的事情是否真的可行。不幸的是,我不记得我当时用的具体情况。所以这里有一个简单的例子,虽然有很多更好的方法来解决这个问题,但请忽略这些:

def test(func, arg1, arg2):
    return func(arg1, arg2, flag1=True, flag2=False) #Only pass the flags if the function accepts them.

def func1(a, b, flag1, flag2):
    ret = a
    if flag1:
        ret *= b
    if flag2:
        ret += b
    return ret

def func2(a, b):
    return a*b

print test(func1, 5, 6) #prints 30

我想到的另一种方法是这样的:

def test(func, arg1, arg2):
    numArgs = len(inspect.getargspec(func).args)
    if numArgs >= 4:
        return func(arg1, arg2, True, False)
    elif numArgs == 3:
        return func(arg1, arg2, True)
    else:
        return func(arg1, arg2)

print test(func2, 5, 6) #prints 30

或者使用try..except..块

但是有没有更好的方法来做到这一点,而不需要改变func1和func2呢?

(编辑):根据Max S提供的解决方案,我觉得这是最好的方法:

def callWithOptionalArgs(func, *args):
    argSpec = inspect.getargspec(func)
    lenArgSpec = len(argSpec.args or ())
    argsToPass = args[:lenArgSpec] #too many args
    defaults = argSpec.defaults or ()
    lenDefaults = len(defaults)
    argsToPass += (None, )*(lenArgSpec-len(argsToPass)-lenDefaults) #too few args
    argsToPass += defaults[len(argsToPass)+len(defaults)-lenArgSpec:] #default args

    return func(*argsToPass)
print callWithOptionalArgs(func1, 5, 6, True) #prints 30
print callWithOptionalArgs(func2, 5, 6, True) #prints 30

2 个回答

0

如果我理解得没错,你是想通过test这个函数来同时调用func1和func2。

def test(func, arg1, arg2):
    try:
        return func(arg1, arg2, flag1=True, flag2=False)
    except TypeError:
        return func(arg1, arg2)


def func1(a, b, flag1, flag2):
    ret = a
    if flag1:
        ret *= b
    if flag2:
        ret += b
    return ret

def func2(a, b):
    return a*b

print test(func1, 5, 6) #prints 30
print test(func2, 5, 6) #prints 30
1

检查函数是唯一一种可以明确区分参数数量不同的函数的方法,而不需要改变或装饰原来的函数。我对你的包装函数唯一的建议就是让它能够处理任意数量的参数:

def padArgsWithTrue(func, *args):
    passed_args = list(args)
    num_args = len(inspect.getargspec(func).args)
    passed_args += [True] * (num_args - len(args))
    return func(*passed_args)

print padArgsWithTrue(lambda x,y,z,w: (x*y, z, w), 5, 6)

编辑:请注意,这个方法不适用于参数数量可变的函数或者带有关键字参数的函数。在写出完整的解决方案之前,你需要先决定如何处理这些情况。

撰写回答