这是听了Egon老师林海峰老师课的笔记

一、什么是可变长参数

可变长指的是实参值的个数不固定 而实参有按位置和按关键字两种形式定义,

针对这两种形式的可变长,形参对应有两种解决方案来完整地存放它们,分别是*args,**kwargs

下面我将为大家依依介绍它们的存在:

补充:

#1、位置参数:按照从左到右的顺序定义的参数
        位置形参:必选参数
        位置实参:按照位置给形参传值
def func(a,b):
    print(a,b)
func(1,2)# -->1,2

#2、关键字参数:按照key=value的形式定义的实参
        无需按照位置为形参传值
        注意的问题:
                1. 关键字实参必须在位置实参右面
                2. 对同一个形参不能重复传值
def func(a,b):
    print(a,b)
func(b=1,a=2)# -->2,1

#3、默认参数:形参在定义时就已经为其赋值
        可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参)
        注意的问题:
                1. 只在定义时赋值一次
                2. 默认参数的定义应该在位置形参右面
                3. 默认参数通常应该定义成不可变类型
def func(a=1,b=2):
    print(a,b)
func()# -->1,2

二、关于*args参数的那点事:

# 可变长度的位置参数
# *形参名:用来接收溢出的位置实参,溢出的位置实参会被*保存成元组的格式然后赋值给紧跟其后的形参名
# *后跟的可以是任意名字,但是约定俗成应该是args
 def func(x,y,*z):
     print(x,y,z)

 func(1,2,3,4,5)#实参溢出的3,4,5会以元组的形式赋值给*z
# 其实args也只是一个变量名而已,真正起作用的是*这个符号
# 输出结果:1 2 (3, 4, 5)

def my_sum(*x):# 规范命名为*args --》应该写成--》def my_sum(*args)(*args是一种命名规范,当其它程序看到它时就会明白这是个可变长参数)
    res = 0
    for item in x:
        res += x
    return res

res = my_sum(1, 2, 3, 4, 5, 6)
print(res)
# 输出结果: 21

三、来为大家讲下**kwargs吧

# 可变长度的关键子参数
# **形参名:用来接收溢出的关键子实参,溢出的关键字实参会被*保存成字典的格式然后赋值给紧跟其后的形参名
# **后跟的可以是任意名字,但是约定俗成应该是kargs

def func(x, y, **kargs):
    print(x, y, kargs)

func(1, y=2, a=1, c=3)  # a=1,c=3是溢出的关键字实参
# 运行结果为: 1 2 {'a': 1, 'c': 3}

四、让我们更加深刻的来探讨它们的密码吧

# *可以用在实参中,实参中带*,先*后的值打散成位置实参
def func(x,y,z):
    print(x,y,z)

func(*[11,22,33])#==> func(11,22,33)   []里面的元素个数必须与位置形参个数一样

# 输出结果: 11 22 33


# 形参与实参中都带*
def func(x, y, *args):
    print(x, y, args)


func(1, 2, *[3, 4, 5, 6])  # 打散成func(1,2,3,4,5,6)==>输出 1,2(3,4,5,6)
func(1, 2, [3, 4, 5, 6])  # ==》输出 1,2,([3,4,5,6])
func(*'hello')  # 打散成func('h','e','l','l','o')==》输出  h e('l','l','o')
# 输出结果: 
'''
1 2 (3, 4, 5, 6)
1 2 ([3, 4, 5, 6],)
h e ('l', 'l', 'o')
'''

# **可以用在实参中(**后跟的只能是字典),实参中带**,先**后的值打散成关键字实参
def func(x,y,z):
    print(x,y,z)

func(*{'x':1,'y':2,'z':5})#打散成 func('x','y','z')
# 输出结果:x y z

func(**{'x':1,'y':2,'z':5})#打散成 func(x=1,y=2,z=5)
# 输出结果:1 2 5

def func(x, y, **kwargs):
    print(x, y, kwargs)


func(**{'x': 1111, 'y': 2222, 'a': 3333, 'b': 4444})  # 打散成 func(x=1111,y=2222,a=3333,b=4444)
# 输出结果:1111 2222 {'a': 3333, 'b': 4444}

# 混用  *args必须放在**kwargs之前
# 在定义函数时,*后定义的参数,如下所示,称之为命名关键子参数
# 命名关键子实参必须按照key=value形式为其传参

def func(x, y, *, a, b):  # 其中,a和b称之为命名关键子参数
    print(x, y)
    print(a, b)

func(1,2,a=22,b=44)
#输出结果: 1 2

def func(x, y, *, a=2222, b):  # 命名关键字形参中默认赋值的参数不用必须在后面
    print(x, y)
    print(a, b)

func(1, 2, b=44)
# 输出结果:
'''
1 2
2222 44
'''

# 组合使用
# 位置形参,默认形参,*args,命名关键字形参,**kwargs  位置按照如下顺序
def foo(x, y, *args, a=1, b, **kwargs):
    print(x, y)
    print(args)
    print(a)
    print(b)
    print(kwargs)


foo(1, 2, 3, 4, 5, b=3, c=4, d=5)
# 输出结果
'''
1 2
(3, 4, 5)
1
3
{'c': 4, 'd': 5}
'''

def func(x,y,z,a,b,c):
    print(x)
    print(y)
    print(a)
    print(b)
    print(c)

# func(11,y=22,*[33,44],**{'b':55,'c':66})
# 打散 func(11,y=22,33,44,b=55,c=66)会报错,位置实参33此时在关键字实参y=22后面(位置形参应该在关键字形参后面)

func(11, 33, 44, a=22, **{'b': 55, 'c': 66})
# 输出结果
'''
11
33
22
55
66
'''

func(11,33,44,a=22,b=55,c=66)
# 输出结果
'''
11
33
22
55
66
'''