关于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脚本生成Android SALT扰码的方法
Sep 18 Python
python实现堆栈与队列的方法
Jan 15 Python
Python使用matplotlib实现在坐标系中画一个矩形的方法
May 20 Python
Python实现模拟时钟代码推荐
Nov 08 Python
python 多维切片之冒号和三个点的用法介绍
Apr 19 Python
浅谈python标准库--functools.partial
Mar 13 Python
python批量读取文件名并写入txt文件中
Sep 05 Python
python如何从文件读取数据及解析
Sep 19 Python
使用django和vue进行数据交互的方法步骤
Nov 11 Python
tensorflow实现对张量数据的切片操作方式
Jan 19 Python
Selenium基于PIL实现拼接滚动截图
Apr 10 Python
Python面向对象多态实现原理及代码实例
Sep 16 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
PHP文件操作实现代码分享
2011/09/01 PHP
php错误级别的设置方法
2013/06/17 PHP
php简单实现单态设计模式的方法分析
2017/07/28 PHP
PHP面向对象五大原则之开放-封闭原则(OCP)详解
2018/04/04 PHP
arguments对象
2006/11/20 Javascript
jquery监听div内容的变化具体实现思路
2013/11/04 Javascript
js通过元素class名字获取元素集合的具体实现
2014/01/06 Javascript
javascript获取函数名称、函数参数、对象属性名称的代码实例
2014/04/12 Javascript
javascript实现瀑布流加载图片原理
2016/02/02 Javascript
jQuery设置单选按钮radio选中/不可用的实例代码
2016/06/24 Javascript
JavaScript制作颜色反转小游戏
2016/09/25 Javascript
js实现砖头在页面拖拉效果
2020/11/20 Javascript
基于Bootstrap仿淘宝分页控件实现代码
2016/11/07 Javascript
微信小程序实现拖拽 image 触摸事件监听的实例
2017/08/17 Javascript
基于vue.js中关于下拉框的值默认及绑定问题
2018/08/22 Javascript
用POSTMAN发送JSON格式的POST请求示例
2018/09/04 Javascript
读懂CommonJS的模块加载
2019/04/19 Javascript
nodejs中request库使用HTTPS代理的方法
2019/04/30 NodeJs
layui前端时间戳转化实例
2019/11/15 Javascript
使用Python的urllib2模块处理url和图片的技巧两则
2016/02/18 Python
python使用正则表达式的search()函数实现指定位置搜索功能
2017/11/10 Python
python高效过滤出文件夹下指定文件名结尾的文件实例
2018/10/21 Python
Python对ElasticSearch获取数据及操作
2019/04/24 Python
python机器人运动范围问题的解答
2019/04/29 Python
Django框架登录加上验证码校验实现验证功能示例
2019/05/23 Python
Python 3.6打包成EXE可执行程序的实现
2019/10/18 Python
python 实现分组求和与分组累加求和代码
2020/05/18 Python
如何用用Python将地址标记在地图上
2021/02/07 Python
对CSS3选择器的研究(详解)
2016/09/16 HTML / CSS
html5+css3气泡组件的实现
2014/11/21 HTML / CSS
详解css3 flex弹性盒自动铺满写法
2020/09/17 HTML / CSS
Champs Sports加拿大:北美最大的以商场为基础的专业运动鞋和服装零售商之一
2018/05/01 全球购物
电子信息毕业生自荐信
2013/11/16 职场文书
会计专业的自荐信
2013/12/12 职场文书
港澳通行证委托书怎么写
2014/08/02 职场文书
HTML+VUE分页实现炫酷物联网大屏功能
2021/05/27 Vue.js