python 函数的参数可分为位置参数, 缺省参数, 可变参数和关键字参数. 其中可变参数和关键字参数又可以进行拆包.
位置参数
看下面程序:
def fun1(a, b):
print("a --" + str(a))
print("b --" + str(b))
- return a + b
- print(fun1(2, 3))
显然, 程序结果:
- a ---- 2
- b ---- 3
- 5
这里的函数 fun1 中的参数 a 和 b 就是位置参数. 位置参数在调用时, 必须给到具体值.
缺省参数
看下面的代码:
def fun2(a, b, c=0):
print("a --" + str(a))
print("b --" + str(b))
print("c --" + str(c))
- return a + b + c
- print(fun2(2, 3))
- print(fun2(2, 3, 4))
程序输出结果:
- a -- 2
- b -- 3
- c -- 0
- 5
- a -- 2
- b -- 3
- c -- 4
- 9
这里函数 fun2 中, 有三个参数, 其中 a 和 b 是位置参数, c 即是一个缺省参数. 声明函数 fun2 时指定了参数 c=0 , 表示参数 c 的默认值是 0 , 上面程序中两次在调用 fun2 时, 分别传入了两个参数和三个参数. 我们看到, 在传入两个参数时, a 和 b 的值分别是传入的 2 和 3, 其中 c 的值为默认值 0 , 在传入三个参数时, a, b 和 c
值分别是传入的 2, 3, 4 .
很好理解, 在函数定义的时候, 给参数赋了一个默认值, 这样的参数就叫缺省参数, 也叫默认参数.
假设有多个缺省参数, 而我只传入了部分缺省参数会是怎样的情况? 看下面的程序:
def fun2(a, b, c=0, d=0):
print("a --" + str(a))
print("b --" + str(b))
print("c --" + str(c))
print("d --" + str(d))
- return a + b + c + d
- print(fun2(2, 3, 4))
程序执行结果如下:
- a -- 2
- b -- 3
- c -- 4
- d -- 0
- 9
说明, 前面的位置参数是必须要传入的, c 的值是 4 , 而 d 的值是默认值 0 , 这说明, 传入的部分缺省参数会按顺序赋值. 如果偏要将 4 赋给 d , 而 c 用默认参数呢, 则用下面方式调用函数即可:
print(fun2(2, 3, d=4))
程序结果:
- a -- 2
- b -- 3
- c -- 0
- d -- 4
- 9
不止是缺省参数, 位置参数也可以在调用函数时, 也可以指定具体的值赋给哪个参数.
值得注意的是: 定义函数时缺省参数要放在位置参数后面, 如果向下面这样定义:
- def fun2(a, b=0, c):
- return a + b + c
则会报错:
SyntaxError: non-default argument follows default argument
熟悉 java,C# 或者 C++ 等语言的应该知道 "重载方法" 的概念. 参数列表不相同, 包括参数的类型不相同和参数的个数不相同. 在 python 中, 用缺省参数, 正好可以实现重载类似的效果.
可变参数 (不定长参数)
在 Python 函数中, 还可以定义可变参数, 也叫不定长参数. 顾名思义, 可变参数就是传入的参数个数是可变的, 写法为, 在参数前面加上一个 * , 类似于 java 中的不定长参数. 不同的是, java 中不定长参数, 以数组形式存储, 在 python 中, 可变参数则是一个元组. 看下面的程序:
- def fun3(a, *b):
- print(type(a))
- print(a)
- print(type(b))
- print(b)
fun3(1, 2, 3, 4, 5)
输出结果如下:
- <class 'int'>
- 1
- <class 'tuple'>
- (2, 3, 4, 5)
程序中, 函数 fun3 的参数 a 是一个 int 型, 后面 *b 即为可变参数, 在调用时, 可以根据需要传入不同个数的参数, 除去 a 之后, 剩余所有的参数, 都添加到一个元组中.
看下面的调用:
fun3(1, 2, (3, 4, 5), [6, 7], {'x': 8, 'y': 9}, 10, 11)
输出结果如下:
- <class 'int'>
- 1
- <class 'tuple'>
- (2, (3, 4, 5), [6, 7], {'x': 8, 'y': 9}, 10, 11)
结果显示很明确了, 即便我传入列表, 元组, 字典类型的参数, 也会被当做元组的元素, 添加进去.
约定俗成, 函数中的可变参数一般用 *args 来表示.
关键字参数
最后说说 python 的关键字参数. python 关键字参数是在参数前面加上 ** , 和可变参数有点类似, 区别在于, 关键字参数是以字典形式存储. 调用的时候也有区别, 看下面的程序:
- def fun4(a, *b, **c):
- print(type(c))
- print(a)
- print(b)
- print(c)
fun4(1, 2, 3, 4, 5, x=6, y=7)
程序结果:
- <class 'dict'>
- 1
- (2, 3, 4, 5)
- {'x': 6, 'y': 7}
结果显示, 参数 C 的类型是 dict 字典. 在调用时, 需要按照 key = value 的形式传入关键字参数. 约定俗成, 关键字参数一般用 **kwargs 来表示. 按照上面的写法, 我们调用函数时可以随意传入关键字参数, 有时候, 我们需要限定关键字参数的'key' , 这样我们可以使用命名关键字参数. 比如, 上面的程序, 我在调用时关键字参数, 传入了'x' 和'y', 事实上, 我想的话, 还可以传入更多的参数 , 用命名关键字参数, 则可以限定, 只传入'x' 和'y' , 程序如下:
- def fun5(a, *, x, y):
- print(a)
- print(x)
- print(y)
- fun5(1, x=2, y=3)
输出结果:
1 2 3
即用一个 *,, 后面跟上指定的参数. 这样, 你如果多传, 或者少穿关键字参数, 都是不可以的.
可变参数和关键字参数拆包
再回头看前面的例子:
- def fun3(a, *b):
- print(type(a))
- print(a)
- print(type(b))
- print(b)
fun3(1, 2, 3, 4, 5)
执行
fun3(1, 2, (3, 4, 5), [6, 7], {'x': 8, 'y': 9}, 10, 11)
输出结果如下:
- <class 'int'>
- 1
- <class 'tuple'>
- (2, (3, 4, 5), [6, 7], {'x': 8, 'y': 9}, 10, 11)
这里, 传入参数的 (3,4,5) 和 [6,7] 和 {'x': 8, 'y': 9} 都被当作元组里面的元素了. 下面在调用时, 参数前面添加一个 * , 如下:
fun3(1, 2, *(3, 4, 5), *[6, 7], *{'x': 8, 'y': 9}, 10, 11)
结果如下:
- <class 'int'>
- 1
- <class 'tuple'>
- (2, 3, 4, 5, 6, 7, 'x', 'y', 12, 13)
看结果, 在列表或者元组参数前面添加 * 之后, 却反而被拆开成单个元素, 作为元组的元素. 而字典, 只是把它的'key' 拆成单个元素. 这就是可变参数的拆包. 一般, 可变参数的拆包我们只针对元组和列表, 不针对字典.
同样, 对于含有关键字参数的函数, 也可对传入的参数进行拆包, 看下面这个函数:
- def fun6(**kwargs):
- print(kwargs)
下面我调用函数
fun6({'x': 1, 'y': 2})
, 这时候, 程序会报错
因为, 关键字参数, 在调用的时候传参, 需要按照 key = value 的形式传入. 而我现在传入一个字典, 会被当做一个整体, 作为一个位置参数传入. 如果以下面这种方式
fun6(**{'x': 1, 'y': 2})
调用, 则可行, 结果如下:
{'x': 1, 'y': 2}
即通过 ** 将字典拆成了'x'=1 , 'y'=2 的形式. 这就是关键字参数的拆包.
来源: https://www.cnblogs.com/joy99/p/8870188.html