将Python列表作为*args?

3 投票
3 回答
1800 浏览
提问于 2025-04-15 21:16

我有两个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)

撰写回答