使用*args
和获取列表作为输入以使函数具有动态输入数量有什么区别。
与其他方法相比,这两种方法有什么优势吗?
答案 0 :(得分:4)
函数期望的参数类型不同。它们是可以互换的。您选择的内容主要是偏好设置(尽管请参阅答案末尾的例外)。
给出以下定义:
# Separate arguments
def foo(*args):
pass
# Single sequence of arguments
def bar(list_of_args):
pass
x = [1, 2, 3]
这两个调用是等效的:
foo(1, 2, 3)
foo(*x) # Unpack a list before calling
这两个调用是等效的:
bar(x)
bar([1, 2, 3]) # Explicitly pack individual arguments
您在问题中提到了**args
。参数的名称不是很重要;特殊行为由一个或两个*
开头的参数名称表示。一个*
表示任意位置参数,如上所示。两个*
表示任意关键字参数。按照惯例,两个最常用的名称是*args
和**kwargs
。
与上面类似的简短示例:
# Arbitrary keyword arguments
def foo(**kwargs):
pass
# Single dict d
def bar(d):
pass
d = {'a': 1, 'b': 2}
# Equivalent
foo(*d)
foo(a=1, b=2)
# Equivalent
bar(d)
bar(dict(a=1, b=2))
例外:如果函数实际上希望对值进行变异,则不能使用*
/ **
参数有效地替换该值。示例:
def foo(**kwargs):
kwargs['foo'] = 3
这会将'foo'
到3的映射添加到字典,但这是为调用foo
而创建的临时字典。函数外没有任何东西可以引用该字典,因此,foo
返回后,更新不会产生任何作用。
类似的逻辑适用于*args
,但是由于args
是一个元组,并且元组是不可变的,因此无论如何您都无法使用该参数。就是说,如果该函数确实需要一个列表,而不仅仅是一个任意的参数序列,则必须定义函数来处理该列表。
def foo(some_list): # can't use *args here
some_list.append(3)
您不能有效地将其定义为
def foo(*args):
args.append(3)
因为foo
收到一个临时元组,而不是一个列表对象