📅  最后修改于: 2020-08-26 11:42:44             🧑  作者: Mango
一些函数没有参数,另一些具有多个。有时候,我们有一些函数,这些函数带有我们以前不知道的参数。我们可能有可变数量的参数,因为我们想为其他开发人员提供灵活的API,或者我们不知道输入大小。使用Python,我们可以创建函数以接受任意数量的参数。
在本文中,我们将研究如何定义和使用带有可变长度参数的函数。这些函数可以接受数量不明的输入,可以是连续输入,也可以是命名参数。
让我们实现一个函数,该函数查找两个数字之间的最小值。它看起来像这样:
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
你可以不再引用其位置的另一个理由。
另外,函数中只能包含*args
vararg类型。
您可能会认为with的解决方案与*args
list解决方案非常相似。这是因为*args
在内部是一个元组,这是一个类似于列表的可迭代序列。如果要验证其类型,可以在Python解释器中输入代码:
$ python3
>>> def arg_type_test(*args):
... print(type(args))
...
>>> arg_type_test(1, 2)
使用*args
,我们可以按顺序接受多个参数my_min()
。这些参数按其位置进行处理。如果我们想接受多个参数,但要通过名称来引用怎么办?我们将在下一节中了解如何执行此操作。
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
另外,我们允许函数调用者传递的参数的任何数量,只有联想tags
和categories
它们是否设置:
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
现在我们已经了解了对可变长度参数的两种支持,下面让我们看看如何将两者结合在一个函数中。
很多时候,我们希望同时使用*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'}
当混合位置参数和命名参数时,位置参数必须位于命名参数之前。此外,固定长度的参数位于可变长度的参数之前。因此,我们得到这样的订单:
*args
**kwargs
具有所有类型参数的函数如下所示:
def super_function(num1, num2, *args, callback=None, messages=[], **kwargs):
pass
一旦在使用varargs和关键字参数定义和调用函数时遵循该顺序,我们将获得我们期望的行为。
到目前为止,我们已经将*args
and **kwargs
语法用于函数定义。当调用函数时,Python也允许我们使用相同的语法。让我们看看如何!
让我们考虑一个函数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
语法,那么它将字典字典键的名称与函数参数的名称匹配。