关于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 相关文章推荐
python3实现字符串的全排列的方法(无重复字符)
Jul 07 Python
在双python下设置python3为默认的方法
Oct 31 Python
python 重命名轴索引的方法
Nov 10 Python
django 邮件发送模块smtp使用详解
Jul 22 Python
Django 静态文件配置过程详解
Jul 23 Python
Python scipy的二维图像卷积运算与图像模糊处理操作示例
Sep 06 Python
Python多线程获取返回值代码实例
Feb 17 Python
Python GUI库PyQt5样式QSS子控件介绍
Feb 25 Python
Python 读取位于包中的数据文件
Aug 07 Python
分享PyCharm最新激活码(真永久激活方法)不用每月找安装参数或最新激活码了
Dec 27 Python
如何用 Python 制作一个迷宫游戏
Feb 25 Python
python中pycryto实现数据加密
Apr 29 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生成图片验证码的方法
2016/04/15 PHP
php连接oracle数据库的核心步骤
2016/05/26 PHP
ThinkPHP整合datatables实现服务端分页的示例代码
2018/02/10 PHP
PhpStorm本地断点调试的方法步骤
2018/05/21 PHP
php中yar框架实例用法讲解
2020/12/27 PHP
Js setInterval与setTimeout(定时执行与循环执行)的代码(可以传入参数)
2010/06/11 Javascript
js动态添加删除,后台取数据(示例代码)
2013/11/25 Javascript
JavaScript实现网页截图功能
2014/10/16 Javascript
jQuery异步获取json数据方法汇总
2014/12/22 Javascript
解析Vue2.0双向绑定实现原理
2017/02/23 Javascript
JavaScript中最常见的三个面试题解析
2017/03/04 Javascript
深究AngularJS——ng-checked(回写:带真实案例代码)
2017/06/13 Javascript
angular4中关于表单的校验示例
2017/10/16 Javascript
javascript简单实现深浅拷贝过程详解
2019/10/08 Javascript
javascript 内存模型实例详解
2020/04/18 Javascript
Vue-Ant Design Vue-普通及自定义校验实例
2020/10/24 Javascript
vue 页面跳转的实现方式
2021/01/12 Vue.js
Python实现模拟登录及表单提交的方法
2015/07/25 Python
Python中你应该知道的一些内置函数
2017/03/31 Python
Python实现将一个大文件按段落分隔为多个小文件的简单操作方法
2017/04/17 Python
用Python实现随机森林算法的示例
2017/08/24 Python
Pandas探索之高性能函数eval和query解析
2017/10/28 Python
动态规划之矩阵连乘问题Python实现方法
2017/11/27 Python
django xadmin action兼容自定义model权限教程
2020/03/30 Python
JBL美国官方商店:扬声器、耳机等
2019/12/01 全球购物
汇智创新科技发展有限公司
2015/12/06 面试题
妇产科护士自我鉴定
2013/10/15 职场文书
上班迟到检讨书
2014/01/10 职场文书
《跨越海峡的生命桥》教学反思
2014/02/24 职场文书
房屋授权无偿使用证明
2014/11/29 职场文书
干部考察材料范文
2014/12/24 职场文书
同意报考公务员证明
2015/06/17 职场文书
讲座新闻稿
2015/07/18 职场文书
浅谈Redis在直播场景的实践方案
2021/04/27 Redis
用Python爬虫破解滑动验证码的案例解析
2021/05/06 Python
SpringBoot接入钉钉自定义机器人预警通知
2022/07/15 Java/Android