args 和 kwargs 不是必须的,* 和 ** 才是必须的
两者都用于对函数进行参数传递,允许传递不定量的参数给函数
1. Overview
如果对各位同学这两个参数知道的很少,那不妨先输出一下,看看他们是什么:
def func(*args, **kwargs):
print(args)
print(kwargs)
print("------------------")
if __name__ == "__main__":
func()
func(1, 2, 3, 4)
func(A = 1, B = 2, C = 3)
func("python", 123, A = 1, B = 2, C = 3)
输出结果如下:
()
{}
------------------
(1, 2, 3, 4)
{}
------------------
()
{'A': 1, 'B': 2, 'C': 3}
------------------
('python', 123)
{'A': 1, 'B': 2, 'C': 3}
------------------
我们从上面的测试代码中,我们至少可以看到:
-
在函数内部args是一个tuple,kwargs是一个dict、
-
*args和**kwargs是可选参数,调用函数时可以输入,也可以不输入
2. Details
先了解一下关于函数参数的几个概念:
2.1 *args ( Positional Arguments )
本质上是一个tuple
*args用于接收不定量个位置参数,可以是0个,也可以是任意个。
测试如下:
def test_args(para, *args):
print("first para == {0}\n".format(para))
print("args para == {0}".format(args))
for idx, value in enumerate(args):
print("para {0} == {1}".format(idx, value))
if __name__ == "__main__":
test_args("cliffswallow", "hello", "python", 2018)
结果如下:
first para == cliffswallow
args para == ('hello', 'python', 2018)
para 0 == hello
para 1 == python
para 2 == 2018
分析如下:
在上面的测试中,test_args()函数中有两个参数,第一个是必须要输入的参数,第二个是可选参数。在调用该函数时,我们传进去了4个参数,分别是 "cliffswallow", "hello", "python", 2018。第一个参数被当做了必选参数输入,其余三个参数被当做可选参数输入,从输出结果中可以看到,后面三个参数被组装(pack)成为了一个tuple。
当多余的参数以tuple,list,set形式出现时,还可以使用 * 对其进行unpack成位置参数,然后在函数内部又被pack成tuple。因此,多余的位置参数在函数内部都是以tuple形式出现的。
看下面:
def test_args(para, *args):
print("first para == {0}\n".format(para))
print("args para == {0}".format(args))
if __name__ == "__main__":
arg = ("hello", "tuple", 2018) #1
# arg = {"hello", "set", 2018} #2
# arg = ["hello", "list", 2018] #3
test_args("cliffswallow", *arg)
结果如下:
#1
"""
first para == cliffswallow
args para == ('hello', 'tuple', 2018)
"""
#2
"""
first para == cliffswallow
args para == ('hello', 'set', 2018)
"""
#3
"""
first para == cliffswallow
args para == ('hello', 'list', 2018)
"""
分析如下:
tuple,list,set先被 * unpack成位置参数,然后在函数内部又被pack成tuple。
小结一下:在使用*args的地方,可以直接输入多个位置参数,也可以输入在序列/集合参数的前面加上*符号输入。在函数内部都会被pack成tuple形式。
2.2 **kwargs ( Keyword Arguments )
本质上是一个dict
**kwargs用于接收0个或者任意个的关键字参数,这里的关键字就是参数名(联想一下默认参数的形式)
测试如下:
def test_kwargs(para, **kwargs):
print("first para == {0}\n".format(para))
for key, value in kwargs.items():
print("{0} == {1}".format(key, value))
if __name__ == "__main__":
test_kwargs("cliffswallow", python = "py", java = 123, swift = None)
结果如下:
first para == cliffswallow
python == py
java == 123
swift == None
同样地,** 可以将字典unpack成关键字参数
测试如下:
def test_kwargs(**kwargs):
print(test_paras)
for key, value in kwargs.items():
print("{0} == {1}".format(key, value))
if __name__ == "__main__":
test_paras = {"PYTHON":"python", "JAVA":"java", "hello":123}
test_kwargs(**test_paras)
结果如下:
{'PYTHON': 'python', 'JAVA': 'java', 'hello': 123}
PYTHON == python
JAVA == java
hello == 123
小结一下:在使用**kwargs的地方,可以直接输入多个关键字参数,也可以通过在dict类型参数前面加 ** 符号输入,**会自动将dict unpack成关键字参数。
2.3 同时使用*args和**kwargs
同时使用*args和**kwargs时,*args需要在**kwargs前面
测试如下:
def func(name, age = 18, *args, **kwargs):
print(name, age)
print(args)
print(kwargs)
if __name__ == "__main__":
func("cliffswallow", 20, "China", "Beijing", height = 181, weight = 130)
结果如下:
cliffswallow 20
('China', 'Beijing')
{'height': 181, 'weight': 130}
总结一下:在定义的函数参数列表中使用*args和**kwargs,则在调用这个函数时,*args表示可以对函数传递不定量的位置参数,这些参数自动在函数内部组装成一个tuple;**kwargs则允许对函数传递不定量个关键字参数,他们在函数内部被组装成dict。args和kwargs不是必须的,只是两个约定俗成的名字,也可以用其他名词代替。在函数调用时,* 可以将序列/集合 unpack成位置参数,** 可以将字典unpack成关键字参数。