关于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下进行UDP网络编程的教程
Apr 29 Python
Python对列表去重的多种方法(四种方法)
Dec 05 Python
简单实现Python爬取网络图片
Apr 01 Python
Python + selenium + requests实现12306全自动抢票及验证码破解加自动点击功能
Nov 23 Python
关于Pycharm无法debug问题的总结
Jan 19 Python
django框架使用方法详解
Jul 18 Python
python同义词替换的实现(jieba分词)
Jan 21 Python
解决pytorch-yolov3 train 报错的问题
Feb 18 Python
Python selenium模块实现定位过程解析
Jul 09 Python
Flask中jinja2的继承实现方法及实例
Mar 03 Python
Python利用folium实现地图可视化
May 23 Python
Python内置包对JSON文件数据进行编码和解码
Apr 12 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 smarty模版引擎中变量操作符及使用方法
2009/12/11 PHP
centos 5.6 升级php到5.3的方法
2011/05/14 PHP
基于PHP5魔术常量与魔术方法的详解
2013/06/13 PHP
PHP 循环删除无限分类子节点的实现代码
2013/06/21 PHP
使用PHP Socket 编程模拟Http post和get请求
2014/11/25 PHP
使用纯php代码实现页面伪静态的方法
2015/07/25 PHP
PHP查看当前变量类型的方法
2015/07/31 PHP
Laravel 修改默认日志文件名称和位置的例子
2019/10/17 PHP
关于js datetime的那点事
2011/11/15 Javascript
jQuery密码强度检测插件passwordStrength用法实例分析
2015/10/30 Javascript
Jquery和JS获取ul中li标签的实现方法
2016/06/02 Javascript
JavaScript中关于for循环删除数组元素内容时出现的问题
2016/11/21 Javascript
jQuery Mobile漏洞会有跨站脚本攻击风险
2017/02/12 Javascript
Vue.js中用webpack合并打包多个组件并实现按需加载
2017/02/17 Javascript
详解vuex 中的 state 在组件中如何监听
2017/05/23 Javascript
利用require.js与angular搭建spa应用的方法实例
2017/07/19 Javascript
推荐VSCode 上特别好用的 Vue 插件之vetur
2017/09/14 Javascript
javascript实现函数柯里化与反柯里化过程解析
2019/10/08 Javascript
[01:45]典藏宝瓶2+祈求者身心——这就是DOTA2TI9总奖金突破3000万美元的秘密
2019/07/21 DOTA
python机器学习库常用汇总
2017/11/15 Python
Python排序搜索基本算法之归并排序实例分析
2017/12/08 Python
解决安装python3.7.4报错Can''t connect to HTTPS URL because the SSL module is not available
2019/07/31 Python
CSS3制作Dropdown下拉菜单的方法
2015/07/18 HTML / CSS
Emma Bridgewater官网:英国餐具制造商
2019/11/24 全球购物
请解释接口的显式实现有什么意义
2012/05/26 面试题
怎样在 Applet 中建立自己的菜单(MenuBar/Menu)?
2012/06/20 面试题
给校长的建议书600字
2014/05/15 职场文书
社区志愿者活动总结
2014/06/26 职场文书
党员群众路线对照检查材料
2014/08/31 职场文书
民事申诉状范本
2015/05/20 职场文书
大学军训通讯稿
2015/07/18 职场文书
《鸡兔同笼》教学反思
2016/02/19 职场文书
古诗之感恩老师
2019/10/24 职场文书
Vue vee-validate插件的简单使用
2021/06/22 Vue.js
Element实现动态表格的示例代码
2021/08/02 Javascript
vue 自定义组件添加原生事件
2022/04/21 Vue.js