关于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中的应用之translate和maketrans用法详解
Aug 27 Python
Python实现的检测web服务器健康状况的小程序
Sep 17 Python
Python进程间通信用法实例
Jun 04 Python
python结合opencv实现人脸检测与跟踪
Jun 08 Python
Python基础篇之初识Python必看攻略
Jun 23 Python
python3.6.3安装图文教程 TensorFlow安装配置方法
Jun 24 Python
Python FTP文件定时自动下载实现过程解析
Nov 12 Python
python实现上传文件到linux指定目录的方法
Jan 03 Python
如何安装并在pycharm使用selenium的方法
Apr 30 Python
Python如何实现FTP功能
May 28 Python
详解用Python爬虫获取百度企业信用中企业基本信息
Jul 02 Python
matplotlib更改窗口图标的方法示例
Feb 03 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 各种应用乱码问题的解决方法
2010/05/09 PHP
利用PHP如何写APP接口详解
2016/08/23 PHP
用于table内容排序
2006/07/21 Javascript
js中格式化日期时间型数据函数代码
2010/11/08 Javascript
JavaScript获取/更改文本框的值的实例代码
2013/08/02 Javascript
js切换光标示例代码
2013/10/10 Javascript
js toFixed()方法的重写实现精度的统一
2014/03/06 Javascript
Ext修改GridPanel数据和字体颜色、css属性等
2014/06/13 Javascript
JS实现日期时间动态显示的方法
2015/12/07 Javascript
跨域资源共享 CORS 详解
2016/04/26 Javascript
搭建Bootstrap离线文档的方法
2016/12/02 Javascript
微信小程序左右滑动切换页面详解及实例代码
2017/02/28 Javascript
Angular限制input框输入金额(是小数的话只保留两位小数点)
2017/07/13 Javascript
Node.js如何使用Diffie-Hellman密钥交换算法详解
2017/09/05 Javascript
JavaScript数据结构与算法之队列原理与用法实例详解
2017/11/22 Javascript
微信小程序 scroll-view实现锚点滑动的示例
2017/12/06 Javascript
vue组件中的数据传递方法
2018/05/14 Javascript
基于vue中对鼠标划过事件的处理方式详解
2018/08/22 Javascript
vue移动端html5页面根据屏幕适配的四种解决方法
2018/10/19 Javascript
require.js 加载过程与使用方法介绍
2018/10/30 Javascript
详解vue中的computed的this指向问题
2018/12/05 Javascript
微信小程序下拉框组件使用方法详解
2018/12/28 Javascript
浅谈bootstrap layer.open中end的使用方法
2019/09/12 Javascript
用Python的Django框架完成视频处理任务的教程
2015/04/02 Python
Python中使用不同编码读写txt文件详解
2015/05/28 Python
python3.7.0的安装步骤
2018/08/27 Python
Appium+python自动化之连接模拟器并启动淘宝APP(超详解)
2019/06/17 Python
python根据用户需求输入想爬取的内容及页数爬取图片方法详解
2020/08/03 Python
德国鞋子网上商店:Omoda.de
2017/03/31 全球购物
求∏的近似值,直到最后一项的绝对值小于指定的数
2016/02/12 面试题
旅游市场营销方案
2014/03/09 职场文书
实习护士自荐信
2014/06/21 职场文书
机关党员公开承诺书
2014/08/30 职场文书
2014年标准化工作总结
2014/12/17 职场文书
Java中多线程下载图片并压缩能提高效率吗
2021/07/01 Java/Android
原型和原型链 prototype和proto的区别详情
2021/11/02 Javascript