一、在形参中使用*
和**
是比较常见的写法
形参中使用*
和**
的原理可以参考《 * 与 ** 参数问题》这篇文章,讲解非常详细,本文只作一个学习总结。
-
*args
是可变参数,args
接收的是一个元组。比如可以向一个函数传入一个列表(或迭代器),在形参中是使用*
就可以在函数中依次接收这个列表的每一个元素; -
**kw
是关键字参数,kw
接收的是一个字典。比如在收集用户信息的时候,除了必填项之外,我们可以用**
来方便地接收那些未知个数的可选项。 - 在 lambda 表达式中使用
*
和**
lambda 表达式可以当做一个匿名函数,是函数都可以传参,匿名函数的形参中也带有使用*
和**
:
a = lambda *s: s + (2, 'g')
print(a('dd', 'de'))
# 打印出来的结果:('dd', 'de', 2, 'g')
lambda_test = lambda **args: args
print(lambda_test(usr='Obama', age=18))
# 打印出来的结果:{'usr': 'Obama', 'age': 18}
二、当对象为迭代器时,可在实参中使用*
;当对象为一个可迭代的映射时,可在实参中使用**
众所周知,Python 中的可迭代对象分为集合数据类型(list、tuple、dict、set、str)和 generator 两种。
而我们常见的可迭代映射就是 dict 啦。
-
实参中的
*
会获取可迭代对象的 key(索引/键值)
由于获取的是可迭代对象的 key,所以函数的形参可以为位置参数或可变参数。
- 形参为位置参数
def foo(n1, n2, n3, n4, n5):
return n1, n2, n3, n4, n5
d = {'n1': 5, 'n2': 6, 'n3': 7, 'n4': 8, 'n5': 9}
print(foo(*d))
# 打印得到的结果为 ('n1', 'n2', 'n3', 'n4', 'n5')
- 形参为可变参数
def fu(*n):
print(n)
d = {'n1': 5, 'n2': 6, 'n3': 7, 'n4': 8, 'n5': 9}
print(fu(*d))
# 打印得到的结果为 ('n1', 'n2', 'n3', 'n4', 'n5')
以上两个例子中,将实参中的字典对象换成列表、元组或者字符串对象,都是可以的,朋友们可以自己动手尝试一下。
-
实参中的
**
会获取可迭代映射的 value
由于获取的是可迭代对象的 value,所以函数的形参只能为关键字参数,即参数的个数和名称都是固定的。
def foo(n1, n2, n3, n4, n5):
return n1, n2, n3, n4, n5
d = {'n1': 5, 'n2': 6, 'n3': 7, 'n5': 8, 'n4': 9}
print(foo(**d))
# 打印得到的结果为(5, 6, 7, 9, 8)
如果我们要调用的函数不是关键字形参:
def fu(*n):
print(n)
iterator = 'unique'
print(fu(**iterator))
# 会报错为:TypeError: fu() argument after ** must be a mapping
如果调用函数中的关键字形参名称与传入的实参无法一一对应:
def foo(n1, n2, n3, n4, n5):
return n1, n2, n3, n4, n5
d = {'n1': 5, 'n2': 6, 'n3': 7, 'n4': 8, 'n5': 9, 'n6': 10}
print(foo(**d))
# 会报错为:TypeError: foo() got an unexpected keyword argument 'n6'
更多举例说明请参考《Python 函数参数类型 、* 的区别》这篇文章。