例子
func(1, 2, 3, 4, 5, 6) 函数调用 因为函数定义时 *args前面有形参a, 形参b, *args就接收调用时多余的位置实参
a为1 b为2 *args 为 3 4 5 6 是一个元组。
针对函数调用时的 *
func(1, 2, *[1, 2, 3, 4]) func(1, 2, 1, 2, 3, 4)
函数调用时有* 就应该立马将*后面的列表 元组 字符串之类的迭代器 打散成位置参数来看。
注意 如果 *后面是一个字典的话 那么打散成的位置参数就是字典的key
*可以看做是for循环。
形参中 *args 只能接收多余的位置实参 成为一个元组。不能接收关键实参。
例
def calc(*numbers): sum 0 for n in numbers: sum sum n * n return sum nums [1, 2, 3] # 调用方式1 print(calc(nums[0], nums[1], nums[2])) #调用方式2 print(calc(*nums))
运行结果
14
**kwargs
针对函数定义时 站在形参的角度看 **
接收多余的关键实参 成为一个字典dict。
字典的key是关键实参的变量名 字典的value是关键实参的值。
将字典交给**后面的变量名 这里是kwargs
站在实参的角度看 **
d {‘x’:1, ‘y’:2, ‘z’:333}
func(**d) # 等价于func(x 1,y 2,z 333)
函数调用时 后面可以接一个字典 然后会把字典打散成关键参数的形式 也就是key value的形式。
例
def person(name, age, **kw): print( name: , name, age: , age, other: , kw) #调用方式1 print(person( Michael , 30)) #调用方式2 print(person( Bob , 35, city Beijing )) #调用方式3 print(person( Adam , 45, gender M , job Engineer ))
运行结果
name: Michael age: 30 other: {}
name: Bob age: 35 other: { city : Beijing }
name: Adam age: 45 other: { gender : M , job : Engineer }
5 混合参数时 参数顺序
函数定义时
从左往右 位置形参 *args 默认参数 **kwargs
位置形参 默认参数 *args **kwargs 也可以。
因为函数调用时给的实参满足了位置形参、默认参数之后 会把多余的位置实参给args。这样并不会报错。
但是 **kwargs 必须在 *args后面
默认形参必须在位置形参后面
函数调用时
从左到右 位置实参 *args 关键参数 **kwargs
因为 * args 在函数调用时 会被打散成位置实参 而关键参数必须在位置实参的后面 否则会报错。SyntaxError: positional argument follows keyword argument
*args 必须在 **kwargs后面 否则会报语法错误 SyntaxError: iterable argument unpacking follows keyword argument unpacking
总结
Python的函数具有非常灵活的参数形态 既可以实现简单的调用 又可以传入非常复杂的参数。
默认参数一定要用不可变对象 如果是可变对象 程序运行时会有逻辑错误
要注意定义可变参数和关键字参数的语法
*args是可变参数 args接收的是一个tuple
**kw是关键字参数 kw接收的是一个dict。
以及调用函数时如何传入可变参数和关键字参数的语法
可变参数既可以直接传入 func(1, 2, 3) 又可以先组装list或tuple 再通过*args传入 func(*(1, 2, 3))
关键字参数既可以直接传入 func(a 1, b 2) 又可以先组装dict 再通过**kw传入 func(**{ a : 1, b : 2})。
使用*args和**kw是Python的习惯写法 当然也可以用其他参数名 但最好使用习惯用法。
命名的关键字参数是为了限制调用者可以传入的参数名 同时可以提供默认值。
定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符* 否则定义的将是位置参数。
10.4.3 参数的传递Python参数传递采用的肯定是“传对象引用”的方式。这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象 比如字典或者列表 的引用 就能修改对象的原始值 相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象 比如数字、字符或者元组 的引用 就不能直接修改原始对象 相当于通过“传值’来传递对象。
例
attrList [0, 1, 2, 3, 4, 5] print( 改变前———————————————————————————————— ) print(attrList) def func(i, attrList): attrList[i] attrList[i] * 10



