1. 位置参数
位置参数是指按照函数定义时的参数顺序来传递实参。举个例子:
def greet(name, message):
print(f"{name}, {message}")
greet("Lucy", "Good morning!")
在这个例子中,name
和message
是位置参数,当我们调用greet("Lucy", "Good morning!")
时,"Lucy"
就被赋值给了name
,"Good morning!"
被赋值给了message
。
调用函数时,我们可以根据参数位置来传递实参,例如:greet("John", "How are you?")
。如果我们传递的参数位置与函数定义时的顺序不一致,那么会出现错误。
一旦定义了一个位置参数,调用函数时必须传递对应数量的参数值。如果传递的参数数量不对,Python解释器会抛出一个TypeError。
1.1 *args语法:传递任意数量的位置参数
如果我们想传递任意数量的位置参数,可以使用*args
语法,如下所示:
def greet(*names):
for name in names:
print(f"Hello, {name}")
greet("Lucy", "John", "Mike")
在这个例子中,*names
定义了一个元组,接收所有给定的位置参数,Python解释器把这些参数打包成一个元组传递给函数。可以看到,在调用greet
函数时传递三个参数,因为*names
表示可以接收任意数量的位置参数,所以它们都被打包为一个元组,程序输出如下:
Hello, Lucy
Hello, John
Hello, Mike
值得一提的是,通过*args
方式传递位置参数实现的灵活性相当强悍,但对于代码可读性造成一定的影响,因此,使用*args
时建议在函数名和元组形参名之间加上注释对代码进行说明。
2. 默认参数
如果我们写了一个函数,希望部分参数有默认值,一旦函数有了这些默认值,函数调用的代码就会变得简洁明了。这时我们可以使用默认参数。
一个默认参数允许指定一个缺省值,如果未传递这个参数的值,则会使用该缺省值。
下面给一个例子:
def greet(name, message="Good morning!"):
print(f"{name}, {message}")
greet("Lucy")
在这个例子中,我们给message
参数设置了一个默认值"Good morning!"
,因此当我们调用greet("Lucy")
时,"Good morning!"
这个默认值就会被使用。
需要注意的是,如果一个默认参数值被设为一个可变对象(比如Python中的列表或字典),则这个默认参数值在所有函数调用之间共享,这可能会产生意想不到的副作用。
3. 动态参数
当不确定参数个数时,我们可以使用动态参数。
3.1 *args语法:传递任意数量的位置参数
我们已经在位置参数中使用过*args
了,现在我们可以使用*args
参数语法来实现动态参数。下面的例子展示了如何使用*args
来接收任意数量的位置参数:
def greet(*names, message):
for name in names:
print(f"{name}, {message}")
greet("Lucy", "John", "Mike", message="Good morning!")
需要注意的是,从语法上来讲,*args
语法可以和位置参数一起使用也可以不一起使用,它只是表示可以接收任意数量的位置参数而已。
3.2 **kwargs语法:传递任意数量的关键字参数
动态参数也可以接收任意数量的关键字参数,例如下面的例子:
def greet(**names):
for key, value in names.items():
print(f"{key} is {value}")
greet(Lucy="Female", John="Male", Mike="Male")
在这个例子中,我们使用**names
语法定义了一个dict
,函数可以接收任意数量的关键字参数,每一个参数将被绑定到names
字典中。
需要注意的是,从语法上来讲,**kwargs
语法可以和关键字参数一起使用也可以不一起使用,它只是表示可以接收任意数量的关键字参数而已。
4. 关键字参数
我们还可以在函数调用参数列表中使用关键字参数,这时候函数会知道关键字所对应的是哪个参数。
4.1 带有默认值的关键字参数
我们可以使用默认参数语法来带有默认值的关键字参数。
def greet(name, message="Good morning!"):
print(f"{name}, {message}")
greet(name="Lucy")
在这个例子中,我们给message
参数设置了一个默认值"Good morning!"
,然后使用greet(name="Lucy")
来调用函数。因为我们已经指定了name
参数,所以Python解释器知道我们应该把message
参数绑定到默认值"Good morning!"
上。
4.2 带有不带默认值的关键字参数
如果我们在函数定义时不想给某个参数设置默认值,但又希望在函数调用时可以使用关键字参数来传递参数,则可以按照如下示例:
def greet(name1, name2, message):
print(f"{name1}, {name2}, {message}")
greet(name1="Lucy", name2="John", message="Good morning!")
在这个例子中,我们通过name1="Lucy"
语法为name1
参数传递了一个值,然后通过name2="John"
语法为name2
传递了一个值。
值得一提的是,关键字参数在函数调用时可以与位置参数混合使用,但是需要注意一个规则:关键字参数必须放在位置参数的后面。
5. 放在一起看
我们来举个结合前面知识点方便理解的例子。
def greet(*names, message="Good morning!", **emails):
for name in names:
print(f"{name}, {message}")
for key, value in emails.items():
print(f"{key} is {value}")
greet("Lucy", "John", "Mike", message="Good morning!", Lucy="Lucy@example.com", John="John@example.com")
在这个例子中,我们使用了位置参数、默认参数和关键字参数。
我们使用*names
语法来实现动态参数,以便我们可以传递任意数量的位置参数。然后使用之前介绍的默认参数语法将message
设置为缺省字符串"Good morning!"
。最后,我们使用**emails
语法带有任意数量的键值对关键字参数来传递个性化的邮件地址。
从输出结果可以看出程序执行了两步操作。在第一步中,循环遍历所有名字,输出格式化后的问候语。在第二步中,循环遍历所有关键字参数并输出格式化后的结果。
总结
本文主要介绍了四种Python函数参数类型:位置参数、默认参数、动态参数和关键字参数,并且提供了针对每类参数的相应语法和实际应用中的案例样例。Python给函数参数的使用带来了灵活性,以便开发者可以根据自己的需求来定义适当的函数参数,达到半自动化的效果。