python的*与**,在函数的定义与调用过程中,有着不同的作用
打包参数:
一、函数定义时,形参前加*号(如:*args):收集实参中所有的位置参数,打包成新元组并将该元组赋值给args变量
实参位置参数:实参中所有不带形参名的参数均是位置参数(如实参传递:a, b, 1)
示例:
二、函数定义时,形参前带**号(如:**kwargs):收集实参中的所有关键字参数,打包成新字典并将该字典赋值给kwargs变量
实参关键字参数:实参中所有带形参名的参数均是关键字参数(如实参传递:a = 1, b = 2)
示例:
解包参数:
一、在函数调用时,实参前加 *号(如:*list): 将列表、元组、字符串解包成独立的元素作为参数
注意:*号后必须是可迭代序列(list / tuple / str)
示例:
二、在函数调用时实参前加 **号(如:**dict): 将字典解包成独立的关键字参数(键值对)作为参数
注意:**号后必须是dict类型数据
示例:
列表与字典(可变对象)解包传递与不解包传递的差异:
解包与直接传递的差异:
解包传递:解包传递是值传递,修改被传递的值不会影响原始列表的数据;
直接传递:直接传递是引用传递,传递的是原列表的地址给新的变量,对该变量作任意修改将影响原始列表的数据;
列表解包传递后若在函数中修改了被传递进来的元素的值,实际是修改了副本(动态参数打包后新生成的元组),不会改变原列表的数据
解包传递示例:
直接将列表作为参数传递,在函数内若对接收列表的形参作了修改(修改删除元素),原始列表数据也将相应改变
直接传递列表示例:
2、字典解包与直接传递的差异
字典与列表均为可变类型,原理同列表
字典解包传递示例:
直接传递字典示例:
总结:
1、函数定义时,形参前加*或**号是打包,*号是以新元组形式打包实参中所有的位置参数并将新元组赋值给*号后的变量,**是以新字典形式打包实参中的所有关键字参数并将新字典赋值给**号后的变量;
2、调用函数时,实参前加*或**是对序列解包,*号是解包列表/元组/字符串为独立的元素作为参数,**号是解包字典键值对(每一对键值对都将解包成一个关键字参数)为关键字参数作为实参;
3、当形参中使用动态参数(参数带*或**)时,实参可解包序列传递,或需要解包序列传递参数且不确定序列中元素个数时,在形参中可使用动态参数接收;
4、解包列表或字典传递即使在函数中有修改操作,也不会修改原列表与字典的数据;
若直接传递列表或字典时函数内一旦有修改操作则会原列表或字典数据将被修改,因为列表和字典是可变类型,直接传递时实际传递的是列表与字典的内存地址,函数内可通过地址修改原列表与字典;