函数传参是最常用的方法,但是你真的掌握python里参数的传递和使用了吗?之前文章我们介绍了传参的拷贝情况,会不会引起传入参数的变化。本文详细介绍python的函数中*args, **kwargs的使用。
【资料图】
首先我们了解下python里*操作符主要有哪些作用。
常用的数学操作符,比如乘法day_seconds = 24*60*60,次方 5**2=25
def test_splat(): a = [1, 2, 3] # 这里*a之将a解包到新列表 b = [*a, 4, 5, 6] # [1, 2, 3] print("splat list a", a) # 1, 2, 3 print("splat list *a", *a) # [1,2,3,4,5,6] print("splat list b", b) val_1, val_2, *list_3 = b # 1 print("splat val_1", val_1) # 2 print("splat val_2", val_2) # [3, 4, 5, 6] print("splat list_3", list_3)
如上代码所示,*a就是将列表[1,2,3]解包为1,2,3
本文重点就是介绍*的第三个作用:在函数定义和调用的使用。
在定义函数时,*代表收集参数,**代表收集关键字参数;
在调用函数时,*和**都是分配参数用的。
* args 和 ** kwargs 主要用于函数定义,你可以将不定数量的参数传递给一个函数。这里不定的意思是: 预先并不知道,函数使用者会传递多少个参数给你,所在在这个场景下使用这两个关键字。
*args (arguments)表示任何多个无名参数, 它本质上是一个 tuple
** kwargs (keyword arguments)表示关键字参数, 它本质上是一个 dict
注意:使用时必须要求 *args 参数列要在** kwargs 前面 【因为位置参数在关键字参数的前面。】
下面我们用一些实例来熟悉* args 和 ** kwargs的用法。
最简单的传参用法, 参数个数和位置意义对应,但是如果是不定长参数个数,比如配置项,这种传参方法就不适用了
def test_arg(x, y, z): print("test_arg", x, y ,z)test_arg(1, 2, 3)
def test_args(*args): print("test_args args", args, type(args)) for arg in args: print("test_args arg", arg)
我们可以将参数直接传入
test_args("x", "y", 1, 2, 3, [1.0])输出:test_args args ("x", "y", 1, 2, 3, [1.0]) test_args arg xtest_args arg ytest_args arg 1test_args arg 2test_args arg 3test_args arg [1.0]
也可以直接传入一个变量,那传入args和解包后的*args区别是什么呢
args = 1, 2, 3test_args(args)输出:test_args args ((1, 2, 3),) test_args arg (1, 2, 3)输出:test_args(*args)test_args args (1, 2, 3) test_args arg 1test_args arg 2test_args arg 3
知识点:args = 1, 2, 3 是元组类型,做为元组类型作为参数传递,不解包就是一个整体;所以传入元组参数应该传入解包后的*args
def test_kargs(**kargs): print("test_kargs kargs", kargs, type(kargs)) for key,item in kargs.items(): print("test_kargs", key,item)
test_kargs(a="a", b="b", c=1, d=[1,2]) kargs = (a="a", b="b", c=1, d=[1,2]}) test_kargs(**kargs) 输出: test_kargs kargs {"a": "a", "b": "b", "c": 1, "d": [1, 2]} test_kargs a atest_kargs b btest_kargs c 1test_kargs d [1, 2]
知识点:kargs是字典类型,传入字典参数应该传入解包后的**kargs
def test_arg_args_case1(x, y, *args): print("test_arg_args x", x) print("test_arg_args y", y) print("test_arg_args args", args)def test_arg_args_case2(x, *args, y): print("test_arg_args x", x) print("test_arg_args y", y) print("test_arg_args args", args) test_arg_args_case1("x", "y", 1, "A", [1, 2])test_arg_args_case2("x", 1, "A", [1, 2], y="y")
知识点1:按照位置,*args在最后,前面是对应位置的参数,剩下的为变长*args
知识点2:如果*args不在最后,则需要在参数传入时,明确定义 *args后面的变量参数名
def test_args_kwargs_case1(*args, **kwargs): print("args", args, type(args)) print("kwargs", kwargs, type(kwargs))
args = 1, 2, 3kargs = {"arg1":1, "arg2":2,"arg3":3}test_args_kwargs_case1(1, 2, 3, arg1 = 1, arg2= 2, arg3 = 3)输出:args (1, 2, 3) kwargs {"arg1": 1, "arg2": 2, "arg3": 3} test_args_kwargs_case1(args, kargs)输出:args ((1, 2, 3), {"arg1": 1, "arg2": 2, "arg3": 3}) kwargs {} 注意所有参数作为一个tuple传给了*argstest_args_kwargs_case1(args, **kargs)输出:args ((1, 2, 3),) kwargs {"arg1": 1, "arg2": 2, "arg3": 3} 注意,后面的**kargs作为无名参数字典传入,前面传入的是未解包的args元组test_args_kwargs_case1(*args, **kargs)输出:args (1, 2, 3) kwargs {"arg1": 1, "arg2": 2, "arg3": 3} 正确的传入方式
知识点0:传入的是解包后的*args,作为带关键字参数,才会输出args (1, 2, 3)
知识点1:传入的是解包后的**kargs,作为带关键字参数,才会输出kwargs {"arg1": 1, "arg2": 2, "arg3": 3}
知识点2:顺序:必须*args在**kargs之前 test_args_kwargs_case2(**kwargs, *args) 编译报错 * parameter after ** parameter
def test_arg_args_kwargs1(first_arg, *args, second_arg , **kwargs): print("first_arg", first_arg) print("second_arg", second_arg) print("args", args[0], args[1], args, type(args)) print("kwargs", kwargs, type(kwargs))def test_arg_args_kwargs2(*args, first_arg, second_arg , **kwargs): print("first_arg", first_arg) print("second_arg", second_arg) print("args", args[0], args[1], args, type(args)) print("kwargs", kwargs, type(kwargs))def test_arg_args_kwargs3(first_arg, second_arg ,*args, **kwargs): print("first_arg", first_arg) print("second_arg", second_arg) print("args", args[0], args[1], args, type(args)) print("kwargs", kwargs, type(kwargs))
args = 1,2,3kwargs = {"arg1":1, "arg2":2,"arg3":3}# 报错,必须是无关键字在有关键字之前# test_arg_args_kwargs1(first_arg=1, *args, second_arg=2, **kwargs)test_arg_args_kwargs2(*args, first_arg=1, second_arg=2, **kwargs)test_arg_args_kwargs3(1, 2, *args, **kwargs)
知识点1:顺序必须是无关键字在有关键字之前
比如:*args, 带关键字arg, **kwargs; arg, *args, **kwargs
建议最好按arg, *args, **kwargs的顺序传入
有时候传入参数会使用一些默认值参数,这里也简单介绍下默认值的使用规则。
def test_default_value(num1, num2=2, num3=3): return num1 + num2 + num3sum = test_default_value(1)
知识点:带默认值参数的后面都需要带默认值,参数顺序:不带默认值,带默认值
from typing import Optionaldef test_option_type(num1: int, num2: int,num3: Optional[int] = None): return num1 + num2 + num3
知识点:
规定默认值时,不一定要声明变量所属的类型(说到底Python中的对象、变量名只是一个指针或者说地址罢了),Python是一门动态语言,它总会在Python解释器进程运行的时候去动态地判定一个变量赋值的类型,而之所以在代码中声明静态类型则是为了减少人为错误而提供相应的类型或错误提示,但并不会影响Python的运行!
from typing import Optionaldef test_option_type(num1: int, num2: int,num3: Optional[int] = None): return num1 + num2 + num3
知识点:
可选类型,作用几乎和带默认值的参数等价,不同的是使用Optional会告诉你的IDE或者框架:这个参数除了给定的默认值外还可以是None,而且使用有些静态检查工具如mypy时,对 a: int =None这样类似的声明可能会提示报错,但使用a :Optional[int] = None不会。
如果我们要返回多个参数,一般是如下写法
def test_return_args(): return 1,2,3,4,5,6
a,b,c,d,e,f = test_return_args()print(a,b,c,d,e,f)a, b, _, _, _, _ = test_return_args()print(a, b,_)a, b, *_ = test_return_args()print(a, b, *_)
如果是多个参数中,我们不同调用时刻是想用不同的参数,其他属于冗余参数,可以使用_定义。
如果嫌弃太多冗余太麻烦,就可以使用*_将多余参数进行压包。
那万一我有时候想要a,b,e呢。。还是要很多冗余_,代码不易理解。这里就可以使用具名元组。
def test_namedtuple(): # 构建具名元组 Point = namedtuple("Point", ["x", "y", "z", "value"]) # 添加值,实例化 p1 = Point(1, 1, 1, 5) p2 = Point(x=1, y=2, z=4, value=4) # 解包字典 dict = {"x": 1, "y": 2, "z": 3, "value":4} point = Point(**dict) return point
# 多个返回参数,可以使用具名元组point = test_namedtuple()print("out", point, point[0], point.x)输出:out Point(x=1, y=2, z=3, value=4) 1 1
知识点:namedtuple比dict的优点是,其具有有序性,不可变只读。
参考:
https://blog.csdn.net/qq_44683653/article/details/108990873
https://blog.csdn.net/zkk9527/article/details/88675129
https://blog.csdn.net/GODSuner/article/details/117961990
标签:
精彩推荐
2月5日是正月十五元宵节,广铁集团预计发送旅客123万人次,同比2022年春运增长48 7%,恢复到2019年春运...
2022年12月08日公告发布
2022年12月07日公告发布
5月20日是网络情人节,郑州陈寨花卉市场的一家花店看到一束与众不同的花,竟是用15个钢丝球包扎的。花店...
相较于火车站,机场的免费Wi-Fi速度要快了不少,而全球最快的免费Wi-Fi机场名单,也被统计了出来。美国...
近日,山东省高级人民法院向社会通报全省法院消费者权益司法保护工作情况及10起典型案例。据了解,五年...
南京市19日通报,公安部门在疫情防控期间依法打击各类涉疫违法犯罪行为,截至3月18日,全市共查处各类涉...
日前,北京市人民政府新闻办公室举行新闻发布会,解读《北京市全民科学素质行动规划纲要(2021—2035年)...
去年下半年以来,受多重因素影响,房地产市场出现下行态势。今年以来,各方共同努力持续稳地价、稳房价...
联合国人权理事会第49届会议新疆经济社会发展与人权保障边会18日在广州举办。会议由中国人权研究会、中...
人力资源和社会保障部近日印发《关于开展技术技能类山寨证书专项治理工作的通知》(以下简称《通知》),...
针对网络消费乱象,最高人民法院近期发布《最高人民法院关于审理网络消费纠纷案件适用法律若干问题的规...
当好农民工的“护薪人” 近日,罗某等7名农民工在收到被拖欠的工资后,纷纷打电话向江西省南昌市...
“通讯录里所有人都知道我欠钱了” □ 本报记者 韩丹东 □ 本报见习记者 张守坤 ...
大连宝马车撞人案肇事司机被判死刑 本报讯 记者韩宇 10月29日,辽宁省大连市中级人民法院一审...
医院财务迷上网络赌博输光5000万元公款 □ 本报记者 马维博 □ 本报通讯员 汪宇堂 曹...
辊环车削 雕琢毫厘(工匠绝活) 【绝活看点】 23年来,雷虎始终扎根一线,改进钢材轧制工艺...
交警严查超标电动自行车挪用“白牌” 截至昨晚6时,处罚电动自行车违法行为共计6585笔;下一步将...
明起寒潮来袭 北方气温普降10℃以上 中央气象台预计,本周日北京平原地区最低气温降至-4℃左右...
多种蔬菜价格降幅达五成 包括菠菜、蒿子秆等 预计本月中旬蔬菜恢复供需平衡 本报讯(记者...
资讯News
04-03
04-03
04-03
04-03
04-03
04-03
04-03
04-03
04-03
04-03
04-03
04-03
04-03
04-03
04-03
04-03
04-03
04-03
04-03
04-03
聚焦Policy
当好农民工的“护薪人” 近日,罗某等7名农民工在收到被拖欠的工资后,纷纷打电话向江西省南昌市...
“通讯录里所有人都知道我欠钱了” □ 本报记者 韩丹东 □ 本报见习记者 张守坤 ...
大连宝马车撞人案肇事司机被判死刑 本报讯 记者韩宇 10月29日,辽宁省大连市中级人民法院一审...
医院财务迷上网络赌博输光5000万元公款 □ 本报记者 马维博 □ 本报通讯员 汪宇堂 曹...
辊环车削 雕琢毫厘(工匠绝活) 【绝活看点】 23年来,雷虎始终扎根一线,改进钢材轧制工艺...
交警严查超标电动自行车挪用“白牌” 截至昨晚6时,处罚电动自行车违法行为共计6585笔;下一步将...
明起寒潮来袭 北方气温普降10℃以上 中央气象台预计,本周日北京平原地区最低气温降至-4℃左右...
多种蔬菜价格降幅达五成 包括菠菜、蒿子秆等 预计本月中旬蔬菜恢复供需平衡 本报讯(记者...
北京周日最低气温或达-4℃ 本报讯(记者 赵婷婷)北京青年报记者昨天从中央气象台获悉,新一股...
昌平一家四口确诊新冠肺炎 天通北苑第二社区升级为中风险地区 朝阳两涉疫校区及16所学校停课 ...