传递任意数量的实参
有时你不会提前知道一个函数需要接受多少参数。 幸运的是,Python 允许函数从调用语句中收集任意数量的参数。
例如,考虑一个制作披萨的函数。 它需要接受一定数量的配料,但你无法提前知道一个人想要多少配料。 以下示例中的函数有一个参数 *toppings
,但此参数收集的参数与调用行提供的参数一样多:
def make_pizza(*toppings):
"""Print the list of toppings that have been requested."""
print(toppings)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
参数名称 *toppings
中的星号告诉 Python 创建一个名为 toppings 的元组,其中包含该函数接收的所有值。 函数体中的 print() 调用产生的输出表明 Python 可以处理具有一个值的函数调用和具有三个值的调用。 它以类似的方式处理不同的调用。 请注意,Python 将参数打包到一个元组中,即使该函数只接收一个值:
('pepperoni',)
('mushrooms', 'green peppers', 'extra cheese')
现在我们可以用一个循环来替换 print() 调用,该循环遍历浇头列表并描述所订购的比萨饼:
def make_pizza(*toppings):
"""Summarize the pizza we are about to make."""
print("\nMaking a pizza with the following toppings:")
for topping in toppings:
print(f"- {topping}")
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
无论是接收一个值还是三个值,该函数都会做出适当的响应:
Making a pizza with the following toppings:
- pepperoni
Making a pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese
无论函数接收多少参数,此语法都有效。
结合使用位置实参和任意数量的实参
如果你想让一个函数接受几种不同类型的参数,接受任意数量参数的参数必须放在函数定义的最后。 Python 首先匹配位置参数和关键字参数,然后收集最终参数中的所有剩余参数。
例如,如果函数需要接受比萨饼的 size
,则该参数必须位于参数 *toppings
之前:
def make_pizza(size, *toppings):
"""Summarize the pizza we are about to make."""
print(f"\nMaking a {size}-inch pizza with the following toppings:")
for topping in toppings:
print(f"- {topping}")
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
在函数定义中,Python 将它收到的第一个值分配给参数 size 。 之后的所有其他值都存储在元组的 toppings 。 函数调用首先包含一个大小参数,然后根据需要添加尽可能多的配料。
现在每个披萨都有一个 size 和一些配料(top),每条信息都打印在适当的位置,先显示大小,再显示配料:
Making a 16-inch pizza with the following toppings:
- pepperoni
Making a 12-inch pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese
你会经常看到通用参数名称 |
使用任意数量的命名实参
有时你会想要接受任意数量的参数,但你不会提前知道什么样的信息将传递给函数。 在这种情况下,您可以编写接受调用语句提供的尽可能多的键值对的函数。 一个例子涉及建立用户档案:你知道你会得到关于用户的信息,但你不确定你会收到什么样的信息。 以下示例中的函数 build_profile() 始终接受名字和姓氏,但它也接受任意数量的命名参数:
def build_profile(first, last, **user_info):
"""Build a dictionary containing everything we know about a user."""
user_info['first_name'] = first (1)
user_info['last_name'] = last
return user_info
user_profile = build_profile('albert', 'einstein',
location='princeton',
field='physics')
print(user_profile)
build_profile() 的定义需要名字和姓氏,然后它允许用户传入任意数量的名称值对。 参数 **user_info
前的双星号导致 Python 创建一个名为 user_info 的字典,其中包含函数接收的所有额外名称-值对。 在该函数中,您可以像访问任何字典一样访问 user_info 中的键值对。
在 build_profile() 的主体中,我们将名字和姓氏添加到 user_info 字典中,因为我们总是会从用户那里收到这两条信息,而它们还没有被放入字典中。 然后我们将 user_info 字典返回到函数调用行。
我们调用 build_profile(),将名字 'albert'、姓氏 'einstein' 和两个键值对 location='princeton' 和 field='physics' 传递给它。 我们将返回的 profile 文件分配给 user_profile 并打印 user_profile:
{'location': 'princeton', 'field': 'physics',
'first_name': 'albert', 'last_name': 'einstein'}
返回的字典包含用户的名字和姓氏,在本例中还包含位置和研究领域。 无论在函数调用中提供了多少个额外的键值对,该函数都将起作用。
在编写自己的函数时,您可以通过多种不同方式混合位置值、关键字值和任意值。 了解所有这些参数类型的存在很有用,因为当您开始阅读其他人的代码时,您会经常看到它们。 正确使用不同类型并知道何时使用每种类型需要练习。 现在,请记住使用最简单的方法来完成工作。 随着您的进步,您将学会每次都使用最有效的方法。
你会经常看到用于收集非特定命名参数的参数名称 |