Python中*args和**kwargs的作用

 更新时间:2023年11月03日 15:16:47   作者:云淡丶风轻  
*args和**kwargs,以及单独的*,**到底是啥作用呢?原理是啥呢?读完这篇文章你就彻底明白了,感兴趣的朋友跟随小编一起看看吧

写在前面

读代码的过程中经常见到这种含*args**kwargs的表达:
比如这个该输出什么呢?

def foo(*args):
    print(args)
foo(1, 2, 3, 4, 5)

这个呢?

def foo(a, *args):
    print('a:', a)
    print('args:', args)
foo(1, 2, 3, 4, 5)

还有这个呢?

def bar(a,b,c):
    print(a,b,c)
bar(*[1,2,3])

咦?∗号怎么出现在了一个列表前面?这样对吗?

*args**kwargs,以及单独的*,**到底是啥作用呢?原理是啥呢?读完这篇文章你就彻底明白了!

*args有两部分构成为——*args。这里的重点是*
所以为了讲清楚*args,我们要追根溯源——理解*的作用。
这里敲黑板,重点来了,这也是很多博客写的没有写到的地方:∗的作用,有2个——打包参数(pack)和拆分参数(unpack)!

*argc

打包参数

例1:

def foo(*number):
    print(number)
foo(1, 2, 3, 4, 5)

(1, 2, 3, 4, 5)

我们看到了什么?给函数5个参数,成功运行了,而且输出是参数构成的元组
我们知道,如果number前不加∗号,那么很明显foo()只能接受1个参数,参数给多了少了都要报错。而加上∗,就能成功运行。
那么原理是什么呢?
答案是:∗把函数foo()接受到的多个参数1,2,3,4,5,打包成了元组(1,2,3,4,5),赋值给了形参number。
我们可以验证一下:
例2:

def foo(*number):
    for i in number:
        print(i)
    print(type(number))
foo(1, 2, 3, 4, 5)

1
2
3
4
5
<class 'tuple'>

从例2可以看出,number确实被赋予了(1,2,3,4,5)这个实参。
说话要讲道理,详情参见python官方文档,这里粘个图过来:

例3:

def foo(a, *number):
    print('a:', a)
    print('number:', number)
    for i in number:
        print(i)
    print(type(number))
foo(1, 2, 3, 4, 5)
a: 1
number (2, 3, 4, 5)
2
3
4
5
<class 'tuple'>

从例3可以看出,number接受到的实参变成了(2,3,4,5),第一个参数1被形参a接受走了。
所以这里我们可以给出∗作用的完整版:

∗的作用:函数接受实参时,按顺序分配给函数形参,如果遇到带∗的形参,那么就把还未分配出去的实参以元组形式打包(pack),分配给那个带∗的形参。

可以再多几个例子验证:
例4:

def foo(a, b, *number):
    print('a:', a)
    print('b:', b)
    print('number:', number)
    for i in number:
        print(i)
    print(type(number))
foo(1, 2, 3, 4, 5)
a: 1
b: 2
number: (3, 4, 5)
3
4
5
<class 'tuple'>

例5:

def foo(a, b, *number, c):
    print('a:', a)
    print('b:', b)
    print('c:', c)
    print('number:', number)
    for i in number:
        print(i)
    print(type(number))
foo(1, 2, 3, 4, 5)
Traceback (most recent call last):
  File "C:/Users/PycharmProjects/untitled10/test19.py", line 11, in <module>
    foo(1, 2, 3, 4, 5)
TypeError: foo() missing 1 required keyword-only argument: 'c'

注意例5我特地找了个报错的例子。自己分析一下为啥会报错。答案是:c前面的参数带∗,把剩下的实参都接受走了,c没有传入实参!

到这里,∗的打包(pack)就解释清楚了。
还留一个小尾巴:args是啥?
答案是:args仅仅是一个约定俗成的形参的写法,你写成把别的也没事,但是不利于统一形式。就像我们的例子里,一直用的number,也照样运行正确。

拆分参数

例6:

def bar(a,b,c):
    print(a,b,c)
bar(*[1,2,3])

1 2 3

可以看出,∗这次没有用在函数定义中,而是用在了函数调用中。在本例中的作用是啥呢?
答案是:把打包了的实参(元组或列表),拆分(unpack)成单个的,依次赋值给函数的形参。
在本例中,打包了的实参[1,2,3]被拆分,1赋值给了形参a,2赋值给了形参b,3赋值给了形参c。

∗拆分的作用就这么简单。理解了原理,其他的万变不离其宗。出两个题,练习一下:
练习:以下3段程序中,哪个可以正常运行?
例7:

def bar(a,b):
    print(a,b)
bar(*[1, 2, 3])

例8:

def bar(a, b, c, d):
    print(a, b, c, d)
bar(*[1, 2, 3])

例9:

def bar(a, b, c, d=10):
    print(a, b, c, d)
bar(*[1, 2, 3])

答案是只有例9可以正常运行。因为按照我们讲的原理,例7的实参3没有对应的形参接受,例8的形参d没有实参赋值。

**kwargs

打包参数

上边*args学懂了**kwargs也就很容易明白了。
**kwargs也有两部分构成为——**kwargs。这里的重点是∗∗。没错,kwargs仅仅是一个约定俗成的写法,没有其他特殊含义,换成其他的也照用不误,但是为了代码可读性,最好还是用约定俗成的。
∗∗的作用同样也有两个——打包参数(pack)和拆分参数(unpack)!
但是区别还是有的,简单来说就是:
打包(pack)*args是把多个位置参数打包成元组**kwargs是把多个关键字参数打包成字典
拆分(unpack)*args是把打包了的参数拆成单个的,依次赋值给函数的形参,**kwargs是把字典的键值拆成单个的,依次赋值给函数的形参。
例10

def bar(**number):
    print(number)
bar(a=1, b=2, c=3)

{'a': 1, 'b': 2, 'c': 3}

拆分参数

例11

def bar(a, b, c):
    print(a,b,c)
bar(**{'a': 1, 'b': 2, 'c': 3})

1 2 3

注意这里有个需要注意的地方,就是用∗∗方式拆解字典给形参赋值时,需要字典的键名和函数形参一直,否则会报错,自己试试就知道了。

位置参数,关键字参数,*args**kwargs混用是要有一定顺序的,这里我特地不写了。因为这问题本身应该不是个问题,是学习函数时应该打下的基本功。如果真的需要,可以自己再查一下,加深印象,也比在我这伸手就拿来的好。

到此这篇关于Python中*args和**kwargs的理解的文章就介绍到这了,更多相关Python *args和**kwargs内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • pytorch GPU和CPU模型相互加载方式

    pytorch GPU和CPU模型相互加载方式

    在PyTorch中,保存和加载模型有两种主要方式:直接保存整个模型结构加权重,或者只保存模型的参数,直接保存整个模型的方法简单,但不够灵活,且可能存在模型结构不一致的风险,推荐的做法是只保存模型参数,这种方法需要在加载前定义与原模型结构相同的模型
    2024-09-09
  • python爬虫实现教程转换成 PDF 电子书

    python爬虫实现教程转换成 PDF 电子书

    本文给大家分享的是使用python爬虫实现把《廖雪峰的 Python 教程》转换成PDF的方法和代码,有需要的小伙伴可以参考下
    2017-02-02
  • python基于OpenCV模块实现视频流数据切割为图像帧数据(流程分析)

    python基于OpenCV模块实现视频流数据切割为图像帧数据(流程分析)

    这篇文章主要介绍了python基于OpenCV模块实现视频流数据切割为图像帧数据,这里今天主要是实践一下视频流数据的预处理工作,需要的朋友可以参考下
    2022-05-05
  • 用django设置session过期时间的方法解析

    用django设置session过期时间的方法解析

    这篇文章主要介绍了用django设置session过期时间的方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • python3两数相加的实现示例

    python3两数相加的实现示例

    这篇文章主要介绍了python3两数相加的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • python自动化测试selenium屏幕截图示例

    python自动化测试selenium屏幕截图示例

    这篇文章主要为大家介绍了python自动化测试selenium屏幕截图示例实现,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2021-11-11
  • Python实现自动化处理每月考勤缺卡数据

    Python实现自动化处理每月考勤缺卡数据

    不管是上学还是上班都会统计考勤,有些学校或公司会对每月缺卡次数过多(比如三次以上)的人员进行处罚。本文提供了Python自动处理考勤和日志缺失的方法,需要的可以参考一下
    2022-06-06
  • keras 指定程序在某块卡上训练实例

    keras 指定程序在某块卡上训练实例

    这篇文章主要介绍了keras 指定程序在某块卡上训练实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-06-06
  • python开发之for循环操作实例详解

    python开发之for循环操作实例详解

    这篇文章主要介绍了python开发之for循环操作,以实例形式较为详细的分析了Python中for循环的具体使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • 详解python函数传参是传值还是传引用

    详解python函数传参是传值还是传引用

    本篇文章主要介绍了详解python函数传参是传值还是传引用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01

最新评论