📜  带有* args和** kwargs的Python中的可变长度参数

📅  最后修改于: 2020-08-26 11:42:44             🧑  作者: Mango

介绍

一些函数没有参数,另一些具有多个。有时候,我们有一些函数,这些函数带有我们以前不知道的参数。我们可能有可变数量的参数,因为我们想为其他开发人员提供灵活的API,或者我们不知道输入大小。使用Python,我们可以创建函数以接受任意数量的参数。

在本文中,我们将研究如何定义和使用带有可变长度参数的函数。这些函数可以接受数量不明的输入,可以是连续输入,也可以是命名参数。

通过* args使用许多参数

让我们实现一个函数,该函数查找两个数字之间的最小值。它看起来像这样:

def my_min(num1, num2):
    if num1 < num2:
        return num1
    return num2

my_min(23, 50)
23

它只是检查第一个数字是否小于第二个数字。如果是,则返回第一个数字。否则,返回第二个数字。

如果我们希望找到至少3个数字,则可以向my_min()和更多的if语句添加另一个参数。如果我们的最小值函数需要找到所有不确定数量中的最小值,则可以使用以下列表:

def my_min(nums):
    result = nums[0]
    for num in nums:
        if num < result:
            result = num
    return result

my_min(4, 5, 6, 7, 2)
2

虽然这样做有效,但我们的编码人员现在必须将其数字括在列表中,这并不像我们有两个或三个定义的参数时那样简单。让我们利用可变长度参数来兼顾两者。

可变长度参数(简称varargs)是可以接受未指定输入量的参数。使用这些格式时,程序员无需将数据包装在列表或替代序列中。

在Python中,使用*args语法定义varargs 。让我们重新实现我们的my_min()功能*args

def my_min(*args):
    result = args[0]
    for num in args:
        if num < result:
            result = num
    return result

my_min(4, 5, 6, 7, 2)
2

注意args只是一个名称,您可以将vararg命名为任何名称,只要它以单个星号(*)开头即可。最好不断命名,args以使其立即被识别。

后面的任何参数都*args必须是命名参数-由其名称而不是其位置引用的参数。有了*args你可以不再引用其位置的另一个理由。

另外,函数中只能包含*argsvararg类型。

您可能会认为with的解决方案与*argslist解决方案非常相似。这是因为*args在内部是一个元组,这是一个类似于列表的可迭代序列。如果要验证其类型,可以在Python解释器中输入代码:

$ python3
>>> def arg_type_test(*args):
...     print(type(args))
...
>>> arg_type_test(1, 2)

使用*args,我们可以按顺序接受多个参数my_min()。这些参数按其位置进行处理。如果我们想接受多个参数,但要通过名称来引用怎么办?我们将在下一节中了解如何执行此操作。

在** kwargs中使用许多命名参数

Python可以接受多个关键字参数,通常称为**kwargs。它的行为类似于*args,但是将参数存储在字典中而不是元组中:

def kwarg_type_test(**kwargs):
    print(kwargs)

kwarg_type_test(a="hi")
kwarg_type_test(roses="red", violets="blue")

输出将是:

{'a': 'hi'}
{'roses': 'red', 'violets': 'blue'}

通过使用字典,**kwargs可以保留参数名称,但无法保持其位置。

注意:类似args,您可以使用除之外的任何其他名称kwargs。但是,最佳实践表明您应始终使用kwargs

由于**kwargs是字典,因此您可以像使用其他.items()方法一样对它们进行迭代:

def kwargs_iterate(**kwargs):
    for i, k in kwargs.items():
        print(i, '=', k)

kwargs_iterate(hello='world')

运行时,我们的控制台将显示:

hello = world

当您不确定某个参数是否可用时,关键字参数很有用。例如,如果我们具有将博客文章保存到数据库的功能,则可以保存诸如内容和作者之类的信息。博客文章可能具有标签和类别,尽管并不总是设置这些标签和类别。

我们可以这样定义一个函数:

def save_blog_post(content, author, tags=[], categories=[]):
    pass

另外,我们允许函数调用者传递的参数的任何数量,只有联想tagscategories它们是否设置:

def save_blog_post(content, author, **kwargs):
    if kwargs.get('tags'):
        # Save tags with post
        pass

    if kwargs.get('categories'):
        # Save categories with post
        pass

现在我们已经了解了对可变长度参数的两种支持,下面让我们看看如何将两者结合在一个函数中。

结合Varargs和关键字参数

很多时候,我们希望同时使用*args**kwargs在一起,编写Python库或可重用的代码时尤其如此。对我们来说很幸运,*args并且**kwargs可以很好地玩耍,我们可以通过以下方式使用它们:

def combined_varargs(*args, **kwargs):
    print(args)
    print(kwargs)

combined_varargs(1, 2, 3, a="hi")

如果运行该代码段,您将看到:

(1, 2, 3)
{'a': 'hi'}

当混合位置参数和命名参数时,位置参数必须位于命名参数之前。此外,固定长度的参数位于可变长度的参数之前。因此,我们得到这样的订单:

  1. 已知的位置参数
  2. *args
  3. 已知的命名参数
  4. **kwargs

具有所有类型参数的函数如下所示:

def super_function(num1, num2, *args, callback=None, messages=[], **kwargs):
    pass

一旦在使用varargs和关键字参数定义和调用函数时遵循该顺序,我们将获得我们期望的行为。

到目前为止,我们已经将*argsand **kwargs语法用于函数定义。当调用函数时,Python也允许我们使用相同的语法。让我们看看如何!

使用* args和** kwargs解压缩参数

让我们考虑一个函数add3(),该函数接受3个数字并打印它们的总和。我们可以这样创建它:

def add3(num1, num2, num3):
    print("The grand total is", num1 + num2 + num3)

如果您有一个数字列表,则可以通过指定将哪个列表项用作参数来使用此功能:

magic_nums = [32, 1, 7]

add3(magic_nums[0], magic_nums[1], magic_nums[2])

如果运行此代码,您将看到:

The grand total is 40

在执行此操作的同时,我们可以使用*args语法使其更加简洁:

add3(*magic_nums)

输出是The grand total is 40,就像以前一样。

当我们*args在函数调用中使用语法时,我们正在解压缩变量。通过解压缩,我们意味着要提取列表的各个值。在这种情况下,我们提取列表中的每个元素并将其放在参数中,其中位置0对应于第一个参数。

您也可以类似地打开元组的包装:

tuple_nums = (32, 1, 7)
add3(*tuple_nums) # The grand total is 40

如果要解压缩字典,则必须使用**kwargs语法。

dict_nums = {
    'num1': 32,
    'num2': 1,
    'num3': 7,
}

add3(**dict_nums) # The grand total is 40

在这种情况下,Python将字典关键字与参数名称匹配并设置其值。

就是这样!通过解压缩值而不是指定需要从对象获取值的每个参数,可以更轻松地管理函数调用。

结论

使用Python,我们可以使用*args**kwargs语法在函数中捕获可变数量的参数。使用*args,我们可以在函数的位置处理无限数量的参数。使用**kwargs,我们可以按名称检索无限数量的参数。

虽然一个函数只能有一个参数,每种类型的长度可变,但是我们可以在一个参数中组合两种类型的函数。如果这样做,我们必须确保位置参数在命名参数之前,固定参数在可变长度参数之前。

Python允许我们也将语法用于函数调用。如果我们有一个列表或元组并使用*args语法,它将把每个值解压缩为位置参数。如果我们有字典并使用**kwargs语法,那么它将字典字典键的名称与函数参数的名称匹配。