为什么使用packed * args / ** kwargs而不是传递list / dict?

时间:2015-11-05 11:05:24

标签: python parameter-passing kwargs

如果我不知道函数将传递多少个参数,我可以使用参数打包来编写函数:

def add(factor, *nums):
    """Add numbers and multiply by factor."""
    return sum(nums) * factor

或者,我可以通过传递一个数字列表作为参数来避免参数打包:

def add(factor, nums):
    """Add numbers and multiply by factor.

    :type factor: int
    :type nums: list of int
    """
    return sum(nums) * factor

使用参数打包*args而不是传递数字列表是否有优势?或者是否存在更合适的情况?

3 个答案:

答案 0 :(得分:8)

*args / **kwargs有其优点,通常是在您希望能够传递解包数据结构的情况下,同时保留使用打包数据结构的能力。 Python 3的print()就是一个很好的例子。

print('hi')
print('you have', num, 'potatoes')
print(*mylist)

print()仅采用打包结构然后在函数内扩展它的情况进行对比:

print(('hi',))
print(('you have', num, 'potatoes'))
print(mylist)

在这种情况下,*args / **kwargs非常方便。

当然,如果您希望函数始终传递数据结构中包含的多个参数,如sum()str.join()那样,那么忽略{{1}可能更有意义。语法。

答案 1 :(得分:1)

它是关于API:* args提供了一个更好的接口,因为它声明该方法接受任意数量的参数,就是这样 - 没有进一步的假设。您确定该方法本身不会对包含各种参数的数据结构执行任何其他操作,并且不需要特殊的数据结构。

理论上,您还可以接受值设置为None的字典。为什么不?这是开销和不必要的。对我来说,当你接受varargs时接受一个列表会增加开销。 (正如其中一条评论指出的那样)

此外,varargs是保证调用者和被调用函数之间一致性和良好契约的好方法。不能做出任何假设。

当您需要列表时,您知道需要一个列表!

啊,请注意f(* args)与f(list)不同:第二个想要一个列表,第一个接受任意数量的参数(包括0)。好的,我们将第二个定义为可选参数:

def f(l = []): pass

很酷,现在你有两个问题,因为你必须确保不修改参数l:default parameter values。是什么原因?因为你不喜欢* args。 :)

PS:我认为这是动态语言的最大缺点之一:你不再看到界面了,但是是的!有一个界面!

答案 2 :(得分:1)

这是一个古老的例子,但是要回答@DBrenko关于何时需要* args和** kwargs的查询,我发现的最清楚的例子是当您想要一个函数来运行另一个函数作为其执行的一部分时。举一个简单的例子:

import datetime

def timeFunction(function, *args, **kwargs):
    start = datetime.datetime.now()
    output = function(*args, **kwargs)
    executionTime = datetime.datetime.now() - start
    return executionTime, output 

timeFunction将一个函数和该函数的参数作为其参数。通过使用* args和** kwargs语法,它不仅限于特定功能。