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

Why use packed *args/**kwargs instead of passing list/dict?

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

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 比传递数字列表有优势吗?或者有哪些情况更合适?

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

理论上,您也可以接受值设置为 None 的字典。为什么不?这是开销和不必要的。对我来说,在可以接受可变参数的情况下接受列表会增加开销。 (正如其中一条评论所指出的)

此外,可变参数是保证调用者和被调用函数之间的一致性和良好契约的好方法。无法假设。

何时以及如果您需要一个列表,那么您就知道您需要一个列表!

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

def f(l = []): pass

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

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

*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() 所做的那样,省略 [= 可能更有意义20=]语法。

这有点老了,但是要回答@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 语法,它不限于特定的函数。