关于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 相关文章推荐
采用Psyco实现python执行速度提高到与编译语言一样的水平
Oct 11 Python
python创建进程fork用法
Jun 04 Python
使用py2exe在Windows下将Python程序转为exe文件
Mar 04 Python
解决pycharm界面不能显示中文的问题
May 23 Python
Python 字符串转换为整形和浮点类型的方法
Jul 17 Python
Linux下python3.7.0安装教程
Jul 30 Python
django echarts饼图数据动态加载的实例
Aug 12 Python
win10下安装Anaconda的教程(python环境+jupyter_notebook)
Oct 23 Python
Python求正态分布曲线下面积实例
Nov 20 Python
python实现录制全屏和选择区域录屏功能
Feb 05 Python
字典算法实现及操作 --python(实用)
Mar 31 Python
python机器学习实现oneR算法(以鸢尾data为例)
Mar 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
真正的ZIP文件操作类(php)
2007/07/21 PHP
简单的php缓存类分享     php缓存机制
2014/01/22 PHP
基于thinkPHP3.2实现微信接入及查询token值的方法
2017/04/18 PHP
PHP Beanstalkd消息队列的安装与使用方法实例详解
2020/02/21 PHP
一端时间轮换的广告
2006/06/26 Javascript
彪哥1.1(智能表格)提供下载
2006/09/07 Javascript
用javascript实现兼容IE7的类库 IE7_0_9.zip提供下载
2007/08/08 Javascript
JavaScript的setAttribute兼容性问题解决方法
2013/11/11 Javascript
在每个匹配元素的外部插入新元素的方法
2013/12/20 Javascript
jquery如何通过name名称获取当前name的value值
2013/12/20 Javascript
Javascript玩转继承(三)
2014/05/08 Javascript
javascript 将共享属性迁移到原型中去的实现方法
2016/08/31 Javascript
详解微信小程序开发之下拉刷新 上拉加载
2016/11/24 Javascript
JavaScript中三个等号和两个等号你了解多少
2017/07/04 Javascript
webpack4打包vue前端多页面项目
2018/09/17 Javascript
使用vue-cli4.0快速搭建一个项目的方法步骤
2019/12/04 Javascript
Vue项目中使用flow做类型检测的方法
2020/03/18 Javascript
解析Mac OS下部署Pyhton的Django框架项目的过程
2016/05/03 Python
Python2.7读取PDF文件的方法示例
2017/07/13 Python
快速了解Python开发中的cookie及简单代码示例
2018/01/17 Python
pandas 选择某几列的方法
2018/07/03 Python
Python 使用list和tuple+条件判断详解
2019/07/30 Python
selenium2.0中常用的python函数汇总
2019/08/05 Python
解决python 读取excel时 日期变成数字并加.0的问题
2019/10/08 Python
python 经典数字滤波实例
2019/12/16 Python
基于Python模拟浏览器发送http请求
2020/11/06 Python
python分布式爬虫中消息队列知识点详解
2020/11/26 Python
移动端HTML5实现文件上传功能【附代码】
2016/03/25 HTML / CSS
军用级手机壳,专为冒险而建:Zizo Wireless
2019/08/07 全球购物
葡萄牙航空官方网站:TAP Air Portugal
2019/10/31 全球购物
财务负责人任命书
2014/06/06 职场文书
主题团日活动总结
2014/06/25 职场文书
护理实习生带教计划
2015/01/16 职场文书
会计专业自荐信范文
2015/03/05 职场文书
红色革命电影观后感
2015/06/18 职场文书
MYSQL优化之数据表碎片整理详解
2022/04/03 MySQL