函数参数
Python 的函数具有非常灵活多样的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。从简到繁的参数形态如下:
- 位置参数 (positional argument)
- 默认参数 (default argument)
- 可变参数 (variable argument)
- 关键字参数 (keyword argument)
- 命名关键字参数 (name keyword argument)
- 参数组合
一、位置参数
def functionname(arg1):
"函数_文档字符串"
function_suite
return [expression]
-
arg1
- 位置参数 ,这些参数在调用函数 (call function) 时位置要固定。
这段代码定义了一个名为functionname
的函数,它接受一个位置参数arg1
。
函数体包括一个文档字符串和一个函数体代码(称为 functionsuite
)。文档字符串是对函数功能和使用方法的描述,位于函数定义的第一行,用于提供关于函数的说明和帮助。
函数执行完成后,可能会使用 return
语句返回一个表达式的值(可选)。如果在函数体中没有 return
语句或者没有指定返回值,函数将返回 None
。
例如,以下是一个示例函数的定义:
def greet(name):
"向给定的姓名打招呼,并返回招呼语"
greeting = f"Hello, {name}!"
return greeting
在上述示例中,函数名为 greet
,它接受一个位置参数 name
。文档字符串 "向给定的姓名打招呼,并返回招呼语"
对该函数进行了说明。函数体中的代码用于创建一个招呼语字符串,并将其赋给变量 greeting
。然后,使用 return
语句返回 greeting
变量的值。
二、默认参数
def functionname(arg1, arg2=v):
"函数_文档字符串"
function_suite
return [expression]
-
arg2 = v
- 默认参数 = 默认值,调用函数时,默认参数的值如果没有传入,则被认为是默认值。 - 默认参数一定要放在位置参数 后面,不然程序会报错。
1
【例子】
def printinfo(name, age=8):
print('Name:{0},Age:{1}'.format(name, age))
printinfo('小马') # Name:小马,Age:8
printinfo('小马', 10) # Name:小马,Age:10
这段代码定义了一个名为 printinfo
的函数,并对该函数进行了不同的调用。
函数 printinfo
接受两个参数:name
和 age
,其中 age
参数具有默认值 8
。
在第一次调用时,只传递了一个实参 '小马'
给 printinfo
函数。由于没有提供 age
参数的实参,函数将使用默认值 8
。因此,输出结果为 "Name:小马,Age:8"
。
在第二次调用时,传递了两个实参 '小马'
和 10
给 printinfo
函数。这次提供了 age
参数的实参,函数将使用传递进来的实参值。因此,输出结果为 "Name:小马,Age:10"
。
2
- Python 允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
【例子】
def printinfo(name, age):
print('Name:{0},Age:{1}'.format(name, age))
printinfo(age=8, name='小马') # Name:小马,Age:8
这段代码定义了一个名为 printinfo
的函数,并对该函数进行了调用,使用关键字参数传递实参。
函数 printinfo
接受两个参数:name
和 age
。
在函数的调用中,使用关键字参数的方式指定了参数的值,其中 age=8
表示将值 8
赋给参数 age
,name='小马'
表示将字符串 '小马'
赋给参数 name
。
因此,函数调用 printinfo(age=8, name='小马')
将以指定的顺序打印出 "Name:小马,Age:8"
。
使用关键字参数可以使我们在调用函数时不需要按照特定的顺序来传递实参,而是根据参数名称来传递实参值,提高了代码的可读性和灵活性。
三、可变参数
顾名思义,可变参数就是传入的参数个数是可变的,可以是 0, 1, 2 到任意个,是不定长的参数。
def functionname(arg1, arg2=v, *args):
"函数_文档字符串"
function_suite
return [expression]
-
*args
- 可变参数,可以是从零个到任意个,自动组装成元组。 - 加了星号(*)的变量名会存放所有未命名的变量参数。
【例子】
def printinfo(arg1, *args):
print(arg1)
for var in args:
print(var)
printinfo(10) # 10
printinfo(70, 60, 50)
# 70
# 60
# 50
这段代码定义了一个名为 printinfo
的函数,并对该函数进行了不同的调用。
函数 printinfo
接受一个位置参数 arg1
和一个可变数量的参数 args
,使用了星号 *
来表示该参数可以接收任意数量的实参。
在第一次调用时,只传递了一个实参 10
给 printinfo
函数。因为只有一个实参,所以该实参会被赋给 arg1
,而 args
参数为空。因此,输出结果为 10
。
在第二次调用时,传递了三个实参 70, 60, 50
给 printinfo
函数。其中,70
会被赋给 arg1
,而后面的两个实参 60
和 50
会被收集到一个元组中,并赋给 args
参数。然后,通过循环遍历打印出 arg1
和 args
中的每个元素。因此,输出结果为:
70
60
50
可变数量的参数在函数定义中表示为 *args
,它允许我们传递任意数量的实参给函数。
四、关键字参数
def functionname(arg1, arg2=v, *args, **kw):
"函数_文档字符串"
function_suite
return [expression]
-
**kw
- 关键字参数,可以是从零个到任意个,自动组装成字典。
【例子】
def printinfo(arg1, *args, **kwargs):
print(arg1)
print(args)
print(kwargs)
printinfo(70, 60, 50)
# 70
# (60, 50)
# {}
printinfo(70, 60, 50, a=1, b=2)
# 70
# (60, 50)
# {'a': 1, 'b': 2}
这段代码定义了一个名为 printinfo
的函数,并对该函数进行了不同的调用。
函数 printinfo
接受一个位置参数 arg1
,一个可变数量的参数 args
(使用了星号 *
),以及一个可变数量的关键字参数 kwargs
(使用了两个星号 **
)。
在第一次调用时,传递了三个实参 70, 60, 50
给 printinfo
函数。其中,70
会被赋给 arg1
,而后面的两个实参 60
和 50
会被收集到一个元组中,并赋给 args
参数。关键字参数 kwargs
为空字典。然后,分别打印出 arg1
、args
和 kwargs
的值。因此,输出结果为:
70
(60, 50)
{}
在第二次调用时,传递了五个实参 70, 60, 50, a=1, b=2
给 printinfo
函数。其中,70
会被赋给 arg1
,而后面的两个实参 60
和 50
会被收集到一个元组中,并赋给 args
参数。关键字参数 a=1
和 b=2
会被收集到一个字典中,并赋给 kwargs
参数。然后,分别打印出 arg1
、args
和 kwargs
的值。因此,输出结果为:
70
(60, 50)
{'a': 1, 'b': 2}
使用可变数量的参数和关键字参数可以使函数更加灵活,允许我们传递不同数量的实参和关键字实参给函数。
「可变参数」和「关键字参数」的同异总结如下:
- 可变参数允许传入零个到任意个参数,它们在函数调用时自动组装为一个元组 (tuple)。
- 关键字参数允许传入零个到任意个参数,它们在函数内部自动组装为一个字典 (dict)。
五、命名关键字参数
def functionname(arg1, arg2=v, *args, *, nkw, **kw):
"函数_文档字符串"
function_suite
return [expression]
-
*, nkw
- 命名关键字参数,用户想要输入的关键字参数,定义方式是在nkw 前面加个分隔符*
。 - 如果要限制关键字参数的名字,就可以用「命名关键字参数」
- 使用命名关键字参数时,要特别注意不能缺少参数名。
【例子】
def printinfo(arg1, *, nkw, **kwargs):
print(arg1)
print(nkw)
print(kwargs)
printinfo(70, nkw=10, a=1, b=2)
# 70
# 10
# {'a': 1, 'b': 2}
printinfo(70, 10, a=1, b=2)
# TypeError: printinfo() takes 1 positional argument but 2 were given
这段代码定义了一个名为 printinfo
的函数,并进行了两次调用。
函数 printinfo
接受一个位置参数 arg1
,一个命名关键字参数 nkw
(通过星号 *
后面添加一个逗号来定义),以及一个可变数量的关键字参数 kwargs
(使用了两个星号 **
)。
在第一次调用时,传递了四个实参 70, nkw=10, a=1, b=2
给 printinfo
函数。其中,70
会被赋给 arg1
,关键字实参 nkw=10
会被赋给 nkw
参数,关键字参数 a=1
和 b=2
会被收集到一个字典中,并赋给 kwargs
参数。然后,分别打印出 arg1
、nkw
和 kwargs
的值。因此,输出结果为:
70
10
{'a': 1, 'b': 2}
在第二次调用时,传递了三个实参 70, 10, a=1, b=2
给 printinfo
函数。由于 nkw
是一个命名关键字参数,必须通过关键字形式传递给它一个值。但是,在第二次调用中,实参 10
并没有指定给 nkw
的关键字,而是被错误地视为位置参数传递给了 printinfo
。因此,会引发 TypeError
并提示函数期望的位置参数数量不匹配。正确的调用方式是使用关键字形式传递给 nkw
参数一个值。如第一次调用所示:
printinfo(70, nkw=10, a=1, b=2)
这样就可以成功执行。
- 没有写参数名
nwk
,因此 10 被当成「位置参数」,而原函数只有 1 个位置函数,现在调用了 2 个,因此程序会报错。
六、参数组合
在 Python 中定义函数,可以用位置参数、默认参数、可变参数、命名关键字参数和关键字参数,这 5 种参数中的 4 个都可以一起使用,但是注意,参数定义的顺序必须是:
- 位置参数、默认参数、可变参数和关键字参数。
- 位置参数、默认参数、命名关键字参数和关键字参数。
要注意定义可变参数和关键字参数的语法:
-
*args
是可变参数,args
接收的是一个tuple
-
**kw
是关键字参数,kw
接收的是一个dict
命名关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。定义命名关键字参数不要忘了写分隔符 *
,否则定义的是位置参数。
警告:虽然可以组合多达 5 种参数,但不要同时使用太多的组合,否则函数很难懂。