关于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 中 Meta Classes详解
Feb 13 Python
python subprocess 杀掉全部派生的子进程方法
Jan 16 Python
python中pandas.DataFrame的简单操作方法(创建、索引、增添与删除)
Mar 12 Python
python实现多线程行情抓取工具的方法
Feb 28 Python
tf.truncated_normal与tf.random_normal的详细用法
Mar 05 Python
python去除文件中重复的行实例
Jun 29 Python
Python图片转换成矩阵,矩阵数据转换成图片的实例
Jul 02 Python
python利用插值法对折线进行平滑曲线处理
Dec 25 Python
解决python执行不输出系统命令弹框的问题
Jun 24 Python
如何使用python3获取当前路径及os.path.dirname的使用
Dec 13 Python
使用python自动追踪你的快递(物流推送邮箱)
Mar 17 Python
Django DRF认证组件流程实现原理详解
Aug 17 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
利用curl抓取远程页面内容的示例代码
2013/07/23 PHP
PHP中批量生成静态html(命令行下运行PHP)
2014/04/19 PHP
checkbox 多选框 联动实现代码
2008/10/22 Javascript
JavaScript CSS修改学习第六章 拖拽
2010/02/19 Javascript
js实现页面跳转重定向的几种方式
2014/05/29 Javascript
深入理解javascript构造函数和原型对象
2014/09/23 Javascript
Javascript中的方法链(Method Chaining)介绍
2015/03/15 Javascript
JS+CSS实现分类动态选择及移动功能效果代码
2015/10/19 Javascript
jQuery实现的自定义弹出层效果实例详解
2016/09/04 Javascript
Bootstrap字体图标无法正常显示的解决方法
2016/10/08 Javascript
js实现兼容PC端和移动端滑块拖动选择数字效果
2017/02/16 Javascript
JavaScript中清空数组的三种方式
2017/03/22 Javascript
JS中创建自定义类型的常用模式总结【工厂模式,构造函数模式,原型模式,动态原型模式等】
2019/01/19 Javascript
从组件封装看Vue的作用域插槽的实现
2019/02/12 Javascript
js如何获取访问IP、地区、当前操作浏览器
2019/07/23 Javascript
40行代码把Vue3的响应式集成进React做状态管理
2020/05/20 Javascript
Javascript实现打鼓效果
2021/01/29 Javascript
用实例解释Python中的继承和多态的概念
2015/04/27 Python
python数据结构之图的实现方法
2015/07/08 Python
Python安装官方whl包和tar.gz包的方法(推荐)
2017/06/04 Python
Django教程笔记之中间件middleware详解
2018/08/01 Python
python打印9宫格、25宫格等奇数格 满足横竖斜相加和相等
2019/07/19 Python
Python传递参数的多种方式(小结)
2019/09/18 Python
Pytorch 神经网络—自定义数据集上实现教程
2020/01/07 Python
最小二乘法及其python实现详解
2020/02/24 Python
keras实现多种分类网络的方式
2020/06/11 Python
解决PyCharm不在run输出运行结果而不是再Console里输出的问题
2020/09/21 Python
美国最受欢迎的度假租赁网站:VRBO
2016/08/02 全球购物
用C语言实现文件读写操作
2013/10/27 面试题
学生励志演讲稿
2014/01/06 职场文书
个人现实表现材料
2014/02/04 职场文书
实习推荐信
2014/05/10 职场文书
环境日宣传活动总结
2014/07/09 职场文书
2019年市场部个人述职报告(三篇)
2019/10/23 职场文书
Winsows11性能如何? win11性能测评多核竟比Win10差了10%
2021/11/21 数码科技
动视暴雪取消疫苗禁令 让所有员工返回线下工作
2022/04/03 其他游戏