在不修改函数定义的情况下调用带可选参数的函数
我想知道怎么调用一个函数,并传递一个它可能不会期待的参数。
几天前我遇到了这个问题,找到了一个解决办法。但今天我决定看看我想做的事情是否真的可行。不幸的是,我不记得我当时用的具体情况。所以这里有一个简单的例子,虽然有很多更好的方法来解决这个问题,但请忽略这些:
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)
编辑:请注意,这个方法不适用于参数数量可变的函数或者带有关键字参数的函数。在写出完整的解决方案之前,你需要先决定如何处理这些情况。