关于Python中*args和**kwargs的深入理解


Posted in Python onAugust 07, 2021

1. 理解  *  和  **

Python的赋值语句可以解包将可迭代元素剥离出来

In [6]: a, b, c = [1, 2, 3]
In [7]: a
Out[7]: 1
In [8]: b
Out[8]: 2
In [9]: c
Out[9]: 3

赋值语句可以理解为 a, b, c = [a, b, c] = [1, 2, 3], 将变量a, b, c与目标列表中的数据进行对应.

Python中 * 和 ** 可以理解成一个特殊的解包语法. 将可迭代的对象列表字典等, 获取其中的内容.

关于Python中*args和**kwargs的深入理解

将 * 应用到赋值语句中, 可以解包多个数据对应到一个列表变量.

In [10]: a, *other = [1, 2, 3, 4]
In [11]: a
Out[11]: 1
In [12]: other
Out[12]: [2, 3, 4]
 
In [13]: a, *middle, x = [1, 2, 3, 4]
In [14]: middle
Out[14]: [2, 3]

结合 print 函数理解解包, 第二个print(*['a', 'b', 'c', 'd']) 使用*号将列表解包后, 相当于print('a', 'b', 'c', 'd')

In [15]: print(['a', 'b', 'c', 'd'])
['a', 'b', 'c', 'd']
 
In [16]: print(*['a', 'b', 'c', 'd'])
a b c d

 2.Python函数的参数

Python函数的传参, 支持两种方式, 一种是基于位置传递(Positional Arguments), 一种是基于变量名称传递(Keyword Arguments).

比如定义一个函数func 接受4个参数

In [1]: def func(a, b, c, d):
   ...:    print(a, b, c, d)

可以基于位置传参, (1, 2, 3, 4)根据位置顺序分别赋值给参数a, b, c, d.

In [2]: func(1, 2, 3, 4)
1 2 3 4

也可以基于变量名传递参数, 指定(d=1, c=2, b=3, a=4)分别赋值给对应变量, keyword argument可以乱序

In [3]: func(d=1, c=2, b=3, a=4)
4 3 2 1

或者混合两种参数格式, 组合位置参数和关键字参数. 注意这时不能重复赋值, 即已经传递了位置参数, 不能再通过关键字传参.

In [4]: func(1, 2, d=3, c=4)
1 2 4 3
 
In [5]: func(1, 2, a=3, c=4)
TypeError: func() got multiple values for argument 'a'

 3. 支持任意参数的函数 *args, **kwargs

然后就是我们查看源码时经常看到的语法, *args, **kwargs. 可以看到arg和kwarg即是一个变量, 目的是保存函数中的位置参数和关键字参数,成一个元组和字段对象, 保存args和kwargs就是变量名.

In [1]: def func(var, *args, key=None, **kwargs):
   ...:     print('args: ', args)
   ...:     print('kwargs: ', kwargs)

定义一个除了位置参数 var , 和关键字参数 key 之外还接受任意参数的函数.

调用函数时,传的其他参数就会赋值给 args, 和 kwargs.

In [2]: func('one', 'two', 'three', key='key', four=4, five=5,)
args:  ('two', 'three')
kwargs:  {'four': 4, 'five': 5}
 
In [3]: func('one', 'two', key='key', three='three', four=4, five=5,)
args:  ('two',)
kwargs:  {'three': 'three', 'four': 4, 'five': 5}

可以看到 'one' 赋值给了变量 var,  'two' 和 'three' 传给了元组args,   'key'赋值给了变量 four=4, five=5, 传递给了kwargs , {'four': 4, 'five': 5}.

改变three的传参方式使用three='three'之后, three也去了kwargs.

4. 固定位置参数和关键字参数  /   * 

 Python3.8 中增加了固定参数的关键字 / 和 * , 使用/之前的参数,只能通过位置方式传参, 使用*之后的参数, 只能通过关键字方式传参.

重新写一个最开始的函数

In [1]: def func(a, /, b, *, c, d):
   ...:    print(a, b, c, d)

其中参数a只能通过位置传递, c和d只能通过关键字传递, 参数b不做限制

In [2]: func(1, 2, c=3, d=4)
1 2 3 4
In [3]: func(1, b=2, c=3, d=4)
1 2 3 4
 
In [4]: func(a=1, b=2, c=3, d=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: func() got some positional-only arguments passed as keyword arguments: 'a'
 
In [5]: func(1, 2, 3, d=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: func() takes 2 positional arguments but 3 positional arguments (and 1 keyword-only argument) were given

可以看到, 限制了参数类型之后, 传参方式错误函数会报TypeError, 应用到一些需要限制显式传递参数的场景, 可以提高代码的可读性.

5. **的另一个用法, 字典合并

3.8之后还增加了一个**的新用法, 支持在字典初始化时使用**语法. 合并现有字典的数据时, 可不使用dict.update()函数. 代码示例如下

In [1]: a = {'k': 1, 'm': 2}
In [2]: y = {'y': '3', 'z': 'ii'}
 
In [3]: {**a}
Out[3]: {'k': 1, 'm': 2}
In [4]: {**a, **y}
Out[4]: {'k': 1, 'm': 2, 'y': '3', 'z': 'ii'}
In [5]: {**a, **y, 'uu': 88}
Out[5]: {'k': 1, 'm': 2, 'y': '3', 'z': 'ii', 'uu': 88}

总结:

本文总结了python中*和**的使用方法,  解包时可以获取可迭代对象中的内容.

  1. * 和**在定义函数时使用, 使得函数可以支持任意长度的参数
  2. 解包时可将任意长度数据赋值给一个对象
  3. 关键字 / 和 * 规定参数的传递方式.
  4. 生成新的字典时使用**解包其他字典中的值

到此这篇关于Python中*args和**kwargs深入理解的文章就介绍到这了,更多相关Python中*args和**kwargs内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
从零学python系列之新版本导入httplib模块报ImportError解决方案
May 23 Python
Python实现队列的方法
May 26 Python
python实现windows壁纸定期更换功能
Jan 21 Python
python多线程并发让两个LED同时亮的方法
Feb 18 Python
Python数据类型之String字符串实例详解
May 08 Python
Python3+Pycharm+PyQt5环境搭建步骤图文详解
May 29 Python
python调用pyaudio使用麦克风录制wav声音文件的教程
Jun 26 Python
Django CBV与FBV原理及实例详解
Aug 12 Python
150行Python代码实现带界面的数独游戏
Apr 04 Python
解决jupyter notebook打不开无反应 浏览器未启动的问题
Apr 10 Python
python如何利用Mitmproxy抓包
Oct 10 Python
python模拟点击在ios中实现的实例讲解
Nov 26 Python
python3操作redis实现List列表实例
Aug 04 #Python
Python pandas求方差和标准差的方法实例
Aug 04 #Python
pandas求平均数和中位数的方法实例
Aug 04 #Python
Python NumPy灰度图像的压缩原理讲解
Aug 04 #Python
Python内置数据结构列表与元组示例详解
Python制作动态字符画的源码
Aug 04 #Python
Python进行区间取值案例讲解
Aug 02 #Python
You might like
smarty中先strip_tags过滤html标签后truncate截取文章运用
2010/10/25 PHP
php计算title标题相似比的方法
2015/07/29 PHP
Zend Framework实现Zend_View集成Smarty模板系统的方法
2016/03/05 PHP
PHP使用DOM和simplexml读取xml文档的方法示例
2017/02/08 PHP
Laravel 登录后清空COOKIE的操作方法
2019/10/14 PHP
php设计模式之建造器模式分析【星际争霸游戏案例】
2020/01/23 PHP
简单实用的反馈表单无刷新提交带验证
2013/11/15 Javascript
使用js实现关闭js弹出层的窗口
2014/02/10 Javascript
javascript定义变量时有var和没有var的区别探讨
2014/07/21 Javascript
javascript伸缩型菜单实现代码
2015/11/16 Javascript
js阻止浏览器默认行为的简单实例
2016/05/15 Javascript
利用BootStrap弹出二级对话框的简单实现方法
2016/09/21 Javascript
解决同一页面中两个iframe互相调用jquery,js函数的方法
2016/12/12 Javascript
JavaScript数据结构之二叉查找树的定义与表示方法
2017/04/12 Javascript
深入理解nodejs中Express的中间件
2017/05/19 NodeJs
利用node.js如何创建子进程详解
2017/12/09 Javascript
vue bus全局事件中心简单Demo详解
2018/02/26 Javascript
node错误处理与日志记录的实现
2018/12/24 Javascript
JSON的parse()方法介绍
2019/01/31 Javascript
vue中使用 pako.js 解密 gzip加密字符串的方法
2019/06/10 Javascript
vue elementUI使用tabs与导航栏联动
2019/06/21 Javascript
keep-alive不能缓存多层级路由菜单问题解决
2020/03/10 Javascript
javascript前端实现多视频上传
2020/12/13 Javascript
详解微信小程序(Taro)手动埋点和自动埋点的实现
2021/03/02 Javascript
[53:38]OG vs LGD 2018国际邀请赛淘汰赛BO3 第三场 8.26
2018/08/30 DOTA
Python中列表元素转为数字的方法分析
2016/06/14 Python
详解python中的模块及包导入
2019/08/30 Python
python 生成器和迭代器的原理解析
2019/10/12 Python
在pytorch 中计算精度、回归率、F1 score等指标的实例
2020/01/18 Python
45个非常奇妙的CSS3 特性应用示例
2012/01/01 HTML / CSS
大专毕业生自我鉴定
2013/11/21 职场文书
商场消防管理制度
2014/01/12 职场文书
留守儿童工作方案
2014/06/02 职场文书
2016年“节能宣传周”活动总结
2016/04/05 职场文书
nginx 反向代理之 proxy_pass的实现
2021/03/31 Servers
奇妙的 CSS shapes(CSS图形)
2021/04/05 HTML / CSS