使用任意数量的参数定义函数

任意数量的位置参数:

定义一个能够获取任意数量参数的函数可以通过在其中一个参数前加一个*来完成

def func(*args):
    # args will be a tuple containing all values that are passed in
    for i in args:
        print(i)

func(1, 2, 3)  # Calling it with 3 arguments
# Out: 1
#      2
#      3

list_of_arg_values = [1, 2, 3]
func(*list_of_arg_values)  # Calling it with list of values, * expands the list
# Out: 1
#      2
#      3 

func()  # Calling it without arguments
# No Output 

不能args 提供默认值,例如 func(*args=[1, 2, 3]) 会引发语法错误(甚至不会编译)。

调用函数时,你不能通过名称提供这些,例如 func(*args=[1, 2, 3]) 将引发 TypeError

但是如果你已经在一个数组(或任何其他 Iterable)中有你的参数,你可以像这样调用你的函数:func(*my_stuff)

这些参数(*args)可以通过索引访问,例如 args[0] 将返回第一个参数

任意数量的关键字参数

你可以通过在定义中定义一个带有两个 * 的参数来获取具有名称的任意数量的参数 :

def func(**kwargs):
    # kwargs will be a dictionary containing the names as keys and the values as values
    for name, value in kwargs.items():
        print(name, value)

func(value1=1, value2=2, value3=3)   # Calling it with 3 arguments
# Out: value1 1
#      value2 2
#      value3 3

func()                               # Calling it without arguments
# No Out put

my_dict = {'foo': 1, 'bar': 2}
func(**my_dict)                      # Calling it with a dictionary
# Out: foo 1
#      bar 2

不能提供这些没有名字,例如 func(1, 2, 3) 将提出一个 TypeError

kwargs 是一个普通的本地 python 字典。例如,args['value1'] 将给出参数 value1 的值。务必事先检查是否存在这样的争论或者提出了一个 KeyError

警告

你可以将这些与其他可选参数和必需参数混合,但定义中的顺序很重要。

位置/关键字参数是第一位的。 (必需的参数)。
然后是任意的 *arg 参数。 (可选的)。
接下来是关键字参数。 (需要)。
最后任意关键字 **kwargs 来了。 (可选的)。

#       |-positional-|-optional-|---keyword-only--|-optional-|
def func(arg1, arg2=10 , *args, kwarg1, kwarg2=2, **kwargs):
     pass
  • 必须提供 arg1,否则提出 TypeError。它可以作为位置(func(10))或关键字参数(func(arg1=10))给出。
  • kwarg1 也必须给出,但它只能作为 keyword-argument 提供:func(kwarg1=10)
  • arg2kwarg2 是可选的。如果要更改该值,则应用与 arg1(位置或关键字)和 kwarg1(仅关键字)相同的规则。
  • *args 捕获额外的位置参数。但请注意,arg1arg2 必须作为位置参数提供,以便将参数传递给*argsfunc(1, 1, 1, 1)
  • **kwargs 捕获所有其他关键字参数。在这种情况下,任何参数不是 arg1arg2kwarg1kwarg2。例如:func(kwarg3=10)
  • 在 Python 3 中,你可以单独使用*来指示必须将所有后续参数指定为关键字。例如,Python 3.5 及更高版本中的 math.isclose 函数是使用 def math.isclose (a, b, *, rel_tol=1e-09, abs_tol=0.0) 定义的,这意味着前两个参数可以在位置提供,但可选的第三和第四个参数只能作为关键字参数提供。

Python 2.x 不支持仅关键字参数。可以使用 kwargs 模拟此行为:

def func(arg1, arg2=10, **kwargs):
    try:
        kwarg1 = kwargs.pop("kwarg1")
    except KeyError:
        raise TypeError("missing required keyword-only argument: 'kwarg1'")

    kwarg2 = kwargs.pop("kwarg2", 2)
    # function body ...

关于命名的注意事项

命名可选位置参数 args 和可选关键字参数 kwargs 的约定只是一个约定,你可以使用你喜欢的任何名称,遵循约定是有用的,以便其他人知道你在做什么,甚至你自己以后所以请这样做。

关于唯一性的注释

任何函数都可以定义为没有或一个 *argsnone 或一个 **kwargs 但不能多于一个。*args必须是最后一个位置参数,**kwargs 必须是最后一个参数。尝试使用多个中的任何一个都导致语法错误异常。

关于使用可选参数嵌套函数的注意事项

可以嵌套这样的函数,通常的惯例是删除代码已经处理过的项目但是如果要传递参数,则需要传递带有*前缀的可选位置参数和带有**前缀的可选关键字 args,否则 args 将作为列表或元组和 kwargs 作为单个字典传递。例如:

def fn(**kwargs):
    print(kwargs)
    f1(**kwargs)

def f1(**kwargs):
    print(len(kwargs))

fn(a=1, b=2)
# Out:
# {'a': 1, 'b': 2}
# 2