将Python列表作为*args?
我有两个Python函数,它们的定义中都可以接受可变数量的参数。举个简单的例子:
def func1(*args):
for arg in args:
print arg
def func2(*args):
return [2 * arg for arg in args]
我想把这两个函数组合起来,比如说 func1(func2(3, 4, 5))
,但是我不希望在 func1
中的 args
变成 ([6, 7, 8],)
,我希望它变成 (6, 7, 8)
,就像是直接调用 func1(6, 7, 8)
而不是 func1([6, 7, 8])
。
通常情况下,我会用 func1(*func2(3, 4, 5))
,或者让 func1
检查一下 args[0]
是否是一个列表。但在这个特定的情况下,我不能使用第一个方法,而要使用第二个方法的话,就需要在很多地方进行这样的检查(因为有很多函数充当 func1
的角色)。
有没有人知道该怎么做?我想可能可以用某种方式来检查,但我也可能错了。
3 个回答
1
通常情况下,我会直接用
func1(*func2(3, 4, 5))
这种写法,或者让 func1 检查一下args[0]
是否是一个list
(列表)。可惜的是,在这个特定的情况下,我不能用第一种方法,而如果要用第二种方法,就需要在很多地方都进行这样的检查(因为有很多函数需要像func1
这样处理)。
为什么你不能用第一种方法呢?
>>> def func1(*args):
for arg in args:
print arg
>>> def func2(*args):
return [2 * arg for arg in args]
>>> func2(3, 4, 5)
[6, 8, 10]
>>> func1(1,2,3)
1
2
3
>>> func1(*func2(3, 4, 5))
6
8
10
>>>
如果那样不行,你仍然可以用 func1(*tuple(func2(3, 4, 5)))
这种方式(但你其实不需要这样做)。
4
你可以考虑写一个函数装饰器,用来检查第一个参数是不是一个列表。给现有的函数加上装饰器,比直接修改函数要简单一些。
3
你可以使用一个装饰器,正如Yaroslav所提到的。
下面是一个简单的例子:
def unpack_args(func):
def deco_func(*args):
if isinstance(args, tuple):
args = args[0]
return func(*args)
return deco_func
def func1(*args):
return args
def func2(*args):
return args
@unpack_args
def func3(*args):
return args
print func1(1,2,3) # > (1,2,3)
print func2(1,2,3) # > (1,2,3)
print func1(*func2(1,2,3)) # > (1,2,3)
print func1(func2(1,2,3)) # > ( (1,2,3), )
print func3(func2(1,2,3)) # > (1,2,3)