Python函数可以接受多种类型的参数,这使得编写灵活且功能强大的代码成为可能。以下是几种常见的参数类型及其用法,通过日常生活中的例子来帮助理解。
当一个Python函数接受多种类型的参数时,它们必须按照以下顺序定义:
遵守这个顺序可以确保函数签名清晰并且易于理解,同时也能避免调用函数时出现意外的行为。
举例:想象一下你在做奥利奥饼干,每块饼干有三层:饼干底 奥、夹心 利、饼干顶 奥。如果你不按这个顺序来做,比如先放夹心再放饼干底,那这块饼干就不是我们熟悉的奥利奥而是利奥利了。
示例:
def make_oreo(bottom, filling, top):
print(f"制作奥利奥:\n1. 放置 {bottom}\n2. 加入 {filling}\n3. 盖上 {top}")
# 正确调用
make_oreo("饼干底", "奶油夹心", "饼干顶")
说明:不定长的位置参数允许你传递任意数量的位置参数。这些参数会被收集到一个元组中。使用*args
的主要原因是它提供了灵活性,可以在不知道具体需要多少个参数的情况下编写函数。
数据类型:*args
接收的参数会被打包成一个元组(tuple)。
命名:虽然 args
是约定俗成的名字,但是你可以使用任何有效的变量名代替 args
。例如,你可以使用 *items
或 *elements
等等。然而,使用 args
的好处在于它是一种广泛认可的习惯用法,这使得代码更加易读和可维护。
示例:
def make_multilayer_cookie(*layers):
for i, layer in enumerate(layers, start=1):
print(f"第{i}层: {layer}")
举例:默认参数就像是制作饼干时提供的标准配置。如果你不说要什么夹心,他们就给你经典的奶油夹心;如果你说了,比如“我要巧克力夹心”,那就按你说的做。
示例:
def make_oreo(bottom="饼干底", filling="奶油夹心", top="饼干顶"):
print(f"制作奥利奥:\n1. 放置 {bottom}\n2. 加入 {filling}\n3. 盖上 {top}")
在Python中,关键字参数可以细分为两种类型:
普通的(具名的)关键字参数:这是最常见的情况,你可以在调用函数时使用参数名称来传递值,而不需要关心参数的位置顺序。这些参数可以是必须提供的,也可以是有默认值的。
仅限关键字参数(Keyword-Only Arguments):从Python 3开始引入,这种参数要求在调用函数时必须使用关键字的形式来指定。它们通常定义在有星号*
的地方之后,或者直接跟在不定长位置参数*args
后面。如果函数定义中有仅限关键字参数,那么在调用函数时,这些参数就不能以位置参数的形式提供,只能通过关键字来赋值。
普通的关键字参数允许你在调用函数时指定参数的名字,这样即使不按照定义时的顺序传参也没关系。如果你省略了某些具有默认值的关键字参数,则会使用它们的默认值。
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
# 使用关键字参数调用
greet(name="Alice", greeting="Hi") # 输出: Hi, Alice!
greet(greeting="Good morning", name="Bob") # 输出: Good morning, Bob!
greet(name="Charlie") # 使用默认值,输出: Hello, Charlie!
在这个例子中,greet
函数有两个参数:name
和greeting
。greeting
有一个默认值,所以如果你不提供它,在调用函数时将使用默认的问候语。
仅限关键字参数意味着当你定义一个函数,并且希望某些参数只能通过关键字形式来传递时,你可以这么做。这增加了函数接口的清晰度,因为调用者必须明确地指出每个仅限关键字参数的值。
def greet_with_title(*, title, name):
print(f"Title: {title}, Name: {name}")
# 必须使用关键字参数调用
greet_with_title(title="Mr.", name="John") # 输出: Title: Mr., Name: John
# 下面的调用会引发TypeError,因为我们没有使用关键字参数
# greet_with_title("Mr.", "John") # 这将抛出错误
在这个例子中,greet_with_title
函数定义了两个仅限关键字参数:title
和name
。这意味着无论何时调用这个函数,都必须为这两个参数指定关键字。这样做可以让函数更加明确,减少误用的可能性。
有时你可能会遇到同时使用普通关键字参数和仅限关键字参数的函数。例如:
def complex_greet(name, greeting="Hello", *, polite=True):
message = f"{greeting}, {name}"
if polite:
message += " Have a nice day!"
print(message)
# 调用示例
complex_greet("Alice", greeting="Hi", polite=False) # 输出: Hi, Alice
complex_greet("Bob", polite=True) # 使用默认的greeting,输出: Hello, Bob Have a nice day!
在这里,polite
是一个仅限关键字参数,而name
和greeting
既可以作为位置参数也可以作为关键字参数。因此,当调用complex_greet
时,polite
必须总是通过关键字来指定,而name
和greeting
则可以选择如何传递。
说明:不定长的关键字参数允许你传递任意数量的关键字参数。这些参数会被收集到一个字典中。使用**kwargs
的主要原因是为了处理未知数量和名称的关键字参数,提供更大的灵活性。
数据类型:**kwargs
接收的参数会被打包成一个字典(dict)。
命名:和 *args
类似,kwargs
也是一个习惯用法,但你也可以使用其他任何有效的变量名。选择 kwargs
的理由同样是因为它是社区内广为人知的做法,有助于提高代码的易读性和可维护性。
示例:
def make_special_cookie(**requests):
for key, value in requests.items():
print(f"{key}: {value}")
make_special_cookie(no_sugar="true", extra_chocolate="yes")
举例:假设你有一个购物清单,上面列出了你想买的东西。当你去超市时,你可以把清单上的物品一个个拿出来给收银员扫描,这就是解包参数的作用。
示例:
def buy_items(item1, item2):
print(f"Bought {item1} and {item2}.")
shopping_list = ["apple", "banana"]
buy_items(*shopping_list) # 解包列表,相当于买苹果和香蕉
按照这个顺序定义参数,可以确保函数签名清晰,并且易于理解和使用。使用*args
和**kwargs
不仅是为了提高函数的灵活性和可扩展性,允许处理未知数量的参数,而且采用约定俗成的命名方式如args
和kwargs
也有助于提升代码的易读性和可维护性。