Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Python中*args和**kwargs

Python中*args和**kwargs

作者头像
SEian.G
发布于 2021-07-07 07:07:53
发布于 2021-07-07 07:07:53
1.2K00
代码可运行
举报
文章被收录于专栏:SEian.G学习记录SEian.G学习记录
运行总次数:0
代码可运行

在python开发的过程中,经常会遇到了*args和**kwargs这两个魔法变量,那么它们是什么呢?

其实并不必须写成 *args和 **kwargs(这样写只是一个约定而已)。只有变量前面的 *(星号)才是关键。当然我们可以写成 *var 和 **vars,但是不建议修改。

两者区别 *args 接收多余的位置参数,以元组的形式显示 **kwargs 接收多余的关键字参数,以字典的形式显示 并且同时使用*args和**kwargs时,*args参数必须放在**kwargs 前

让我们通过以下5步来理解:

1. 通过一个函数调用来理解’*’的作用

2. 通过一个函数的定义来理解’*args’的含义

3. 通过一个函数的调用来理解’**’的作用

4. 通过一个函数的定义来解’**kwargs’的含义

5. 通过一个应用实例来说明’args’,’kwargs’应用场景以及为何要使用它

通过一个函数调用来理解’*’的作用

定义一个含三个位置参数的函数”fun”.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> def fun(a,b,c):
... print a,b,c
...

传三个位置参数调用此函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> fun(1,2,3)
1 2 3 #输出

可以看到出入三个位置参数调用此函数,会打印出三个参数

现在我们定义一个含三个整数的数列,并使用’*’

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> l = [1,2,3]
>>> fun(*l)
1 2 3 #输出

‘*’做了什么?

它拆开数列’l’的数值作为位置参数,并把这些位置参数传给函数’fun’来调用。

因此拆数列、传位置参数意味着fun(*l)与fun(1,2,3)是等效的,因为l = [1,2,3]。

试着数列中使用其他数值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> l = [4,8,0]
>>> fun(*l)
4 8 0 #输出

接下来我们试着在数列中放四个数值,调用函数会出现什么情况呢

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> l = [3,6,9,1]
>>> fun(*l)
Traceback (most recent call last):
File "", line 1, in 
TypeError: fun() takes exactly 3 arguments (4 given)

在这次调用中我们并没有得到合适的结果,触发了TypeWrror异常。很容易看到错误内容”fun() takes exactly 3 arguments (4 given)”.

为什么会发生这种情况呢?

数列’l’含有四个数值.因此,我们试图调用’fun(*l)’,’l’中数值拆开传给函数fun作为位置参数。但是,’l’中有四个数值,调用’fun(*l)’相当于调用’fun(3,6,9,1)’,又因为函数’fun’定义中只用三个位置参数,因此我们得到这个错误。同理,同样的步骤,数列’l’中有两个数值情况,注意error内容。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> l = [7,4]
>>> fun(*l)
Traceback (most recent call last):
File "", line 1, in 
TypeError: fun() takes exactly 3 arguments (2 given)

‘*l’与位置参数混合使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> fun(23, *l)
23 7 4

在这里,我们给出一个位置参数23,和从数列’l’拆除的两个数值7和4,因此三个参数23,7和4传给了函数’fun’

通过一个函数的定义来理解’*args’的含义

修改函数的定义:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> def fun(*args):
... print args
...

传一个位置参数调用此函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> fun(13)
(13,)

传多个参数调用此函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> fun(11,93,43)
(11, 93, 43)

‘*args’在函数定义中是做什么用的?

它接收元组作为位置参数,而非是常见的参数列表。在这里,”args”是个元组。在我们解释中不要担心”常见的参数”这部分的理解,这个会在接下来的例子中逐渐明了。在上个例子中,调用函数打印”args”时,他会打印元组中包含的所有数值。

我们重新定义函数,”*args”与”常规参数列表”混合使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> def fun(a, *args):... print "a is ", a
... print "args is ", args
...

在这个函数定义中,参数”a”代表”常规参数列表”。

传四个位置参数调用此函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> fun(11,12,34,43)
a is 11
args is (12, 34, 43)

很容易看到,’a’打印出为11,即第一个位置参数。’a’之后只一个参数’*args’.因此,’args’接收除常规参数之外的位置参数作为元组。因此元组args作为元组接收12,34和43。

我们也可以传一个位置参数来调用此函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> fun(91)
a is 91
args is ()

在这里,我们传的唯一一个参数分配给了常规参数’a’.因此,’args’接收到一个空元组。

既然我们获取了”args”,我们可以提取需要的数值来做我们想做的事情。

重新定义”fun”:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> def fun(a, *args):
... print a
... print "args can receive a tuple of any number of arguments, let's print all that."... for arg in args:
... print arg
...

现在我们传任意个参数来调用此函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> fun(1,5,6,7)
1
args can receive a tuple of any number of arguments, let's print all that.
5
6
7

‘args’既然是元组,我们就可以遍历它。

现在我们考虑使用所有能得到的参数的场景。我们需要使用两个函数,第一个函数带有任意个参数,并通过另外一个函数计算除第一参数的其他参数之和。奇怪的用例,但我们只需回顾我们目前所做的。我们的目的就是在一个函数中获取可变参数,并把这些参数餐给另一个函数。

第一步我们写一个函数计算和。在这个用例中,这个函数会在第一个函数中应用。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> def calculate_sum(*args):
... return sum(args)
...

在这个函数中,我们使用内建函数’sum’,它使用元组或数列作为参数,返回元组所有元素的和。从函数的定义可以看出’args’接收包含传给此函数位置参数的元组.因此,’args’是一个元组,简介的作为函数’sum’的参数。接下来定义另外一个函数,该函数有任意个参数,并利用上一个函数来计算除第一个参数之外的其他参数的和。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> def ignore_first_calculate_sum(a,*iargs):
... required_sum = calculate_sum(*iargs)
... print "sum is ", required_sum
...

我们可以传任意个参数给这个函数。第一个参数被常规参数’a’接收,其他参数被’iargs’作为元组接收。正如我们考虑的案例,计算除第一个参数之外的其他参数的和。

因此,我们用’a’接收第一个参数,’iargs’是包含其他参数的元组。我们用到函数’calculate_sum’,但’calculate_sum’需要多个位置参数作为元组传给’args’。所以在函数’ignore_first_calculate_sum’需要拆元组’iargs’,然后将元素作为位置参数传给’calculate_sum’.注意,用’*’拆元组。

所以,我们这样调用’required_sum=calculate_sum(*iargs)’.

‘required_sum=calculate_sum(iargs)’不能这么调用,因为传给’calculate_sum’之前我们需要unpack数值。不使用’*’将不会unpack数值,也就不能执行想要的动作。调用函数如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> ignore_first_calculate_sum(12, 1,4,5)
sum is 10
 
>>> ignore_first_calculate_sum()
Traceback (most recent call last):
File "", line 1, in 
TypeError: ignore_first_calculate_sum() takes at least 1 argument (0 given)

得到想要的结果。

通过一个函数的调用来理解’**’的作用

定义一个三个参数的函数,并用多种方式调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> def fun(a, b, c):
... print a, b, c
... 
>>> fun(1,5,7)
1 5 7

>>> fun(a=1,b=5,c=7)
1 5 7

使用”**”调用函数,这种方式我们需要一个字典.注意:在函数调用中使用”*”,我们需要元组;在函数调用中使用”**”,我们需要一个字典

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> d={'b':5, 'c':7}
>>> fun(1, **d)
1 5 7

在函数调用中”**”做了什么?

它unpack字典,并将字典中的数据项作为键值参数传给函数。因此,”fun(1, **d)”的写法与”fun(1, b=5, c=7)”等效.

为了更好的理解再多举几个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> d = {'c':3}
>>> fun(1, 4, **d)
1 4 3
 
>>> d = {'a':7, 'b':3, 'c':8}
>>> fun(**d)
7 3 8

让我们制造一些错误:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> d = {'a':7, 'b':3, 'c':8, 'd':90}
>>> fun(**d)
Traceback (most recent call last):
File "", line 1, in 
TypeError: fun() got an unexpected keyword argument 'd'

这次调用等同于’fun(a=7, b=3, c=8, d=90)’,但函数只需要三个参数,因此我们得到TypeError

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> d = {'a':7, 'b':3,'d':90}
>>> fun(**d)
Traceback (most recent call last):
File "", line 1, in 
TypeError: fun() got an unexpected keyword argument 'd'

fun(**d)等同于fun(a=7, b=3, d=90).传给函数”fun”想要的参数个数,但参数列表中并没有’d’,调用中’d’键值参数传给函数导致TypeError.

So, “*” unpacks the dictionary i.e the key values pairs in the dictionary as keyword arguments and these are sent as keyword arguments to the function being called. “” unpacks a list/tuple i.e the values in the list as positional arguments and these are sent as positional arguments to the function being called.

通过函数定义来理解’**kwargs’的含义

重定义函数”fun”:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> def fun(a, **kwargs):
... print a, kwargs
...

此函数只用一个位置参数,因为常规参数列表中只有一个变量’a’.但是通过”**kwargs”,可以传多个键值参数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> fun(1, b=4, c=5)
1 {'c': 5, 'b': 4}
>>> fun(45, b=6, c=7, d=8)
45 {'c': 7, 'b': 6, 'd': 8}

在函数定义中”**kwargs”意味着什么?

用”**kwargs”定义函数,kwargs接收除常规参数列表职位的键值参数字典。在这里’kwargs’是个字典。

重新定义函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> def fun(a, **kwargs):
... print "a is ", a
... print "We expect kwargs 'b' and 'c' in this function"... print "b is ", kwargs['b']
... print "c is ", kwargs['c']
... 
 
>>> fun(1, b=3,c=5)
a is 1
We expect kwargs 'b' and 'c' in this function
b is 3
c is 5

错误调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> fun(1, b=3, d=5)
a is 1
We expect kwargs 'b' and 'c' in this function
b is 3
c is
Traceback (most recent call last):
File "", line 1, in 
File "", line 5, in fun
KeyError: 'c'

上面的调用,位置参数’a’和键值参数’b’都打印出来了。传入的其他键值参数是’d’,函数需要键值参数’c’,并从字典’kwargs’获取。但没有传入键值’c’,引发KeyError.如果传入了键值’c’就不会引发这个错误

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> fun(1, b=3, d=5, c=9)
a is 1
We expect kwargs 'b' and 'c' in this function
b is 3
c is 9

由于’**kwargs’在函数参数列表中,我们可以传任意个键值参数。上面的调用传入了”d”,但函数并没用到。

另外一个错误:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> fun(1, {'b':2, 'c':34})
Traceback (most recent call last):
File "", line 1, in 
TypeError: fun() takes exactly 1 argument (2 given)

正如错误提示,函数’fun’只需要一个位置参数,却给了两个。尽管’kwargs’接收键值参数作为一个字典,但你不能传一个字典作为位置参数给’kwargs’.你可以像下面那样调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> fun(1, **{'b':2, 'c':34})
a is 1
We expect kwargs 'b' and 'c' in this function
b is 2
c is 34

在一个字典前使用”**”可以unpack字典,传字典中的数据项作为键值参数。

通过一个应用实例来说明’args’,’kwargs’应用场景以及为何要使用它

在任何时候继承类和重写方法的,我们应当用到’*args’和’**kwargs’将接收到的位置参数和键值参数给父类方法。通过实例我们更好的理解

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> class Model(object):
...     def __init__(self, name):
...             self.name = name
...     def save(self, force_update=False, force_insert=False):
...             if force_update and force_insert:
...                     raise ValueError("Cannot perform both operations")
...             if force_update:
...                     print "Updated an existing record"
...             if force_insert:
...                     print "Created a new record"
... 

定义一个类,我们可以创建类的对象,类的对象有一个方法’save()’.假设类的对象可以通过save()方法保存到数据库中。通过函数save()参数来决定是否在数据库中创建一条记录或者更新现存的记录。

构造一个新类,类有’Model’的行为,但我们只有检查一些条件后才会保存这个类的对象。这个新类继承’Model’,重写’Model’的’save()’

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> class ChildModel(Model):
...     def save(self, *args, **kwargs):
...             if self.name=='abcd':
...                     super(ChildModel, self).save(*args, **kwargs)
...             else:
...                     return None
... 

实际上对应的保存动作发生在’Model’的’save’方法中。所以我们调用子类的的’save()’方法而非’Model’的方法.子类ChildModel的’save()’接收任何父类save()需要的参数,并传给父类方法。因此,子类’save()’方法参数列表中有”*args”和”**kwargs”,它们可以接收任意位置参数或键值参数,常规参数列表除外。

下面创建ChildModel实体并保存:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> c=ChildModel('abcd')
>>> c.save(force_insert=True)
Created a new record
>>> c.save(force_update=True)
Updated an existing record

这里传兼职参数给对象的save()方法。调用的是子类的save(),It received a dictionary containing the keyword argument in “kwargs”. Then it used “**” to unpack this dictionary as keyword arguments and then passed it to the superclass save(). So, superclass save() got a keyword argument ‘force_insert’ and acted accordingly.

文章链接:https://blog.csdn.net/callinglove/article/details/4548309

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DBA的辛酸事儿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python教程(25)——Python中参数类型详解
当我们在编写函数时,会定义一些占位符,这些占位符就是参数,参数是函数定义中用于接收外部传递值的占位符,这个会帮助我们在函数被调用时接收外部传递的值。在Python当中,有各种各样类型的参数,主要有位置参数、默认参数、关键字参数、可变位置参数、可变关键字参数以及强制关键字参数。
一点sir
2024/01/19
2300
Python教程(25)——Python中参数类型详解
理解 Python 编程中 *args 与 **kwargs 的妙用
在 Python 编程中,*args 和 **kwargs 是两种用于函数定义时处理可变数量的参数的机制。它们分别用于处理位置参数(*args)和关键字参数(**kwargs)。这两个机制提高了函数的灵活性和可重用性,允许开发者编写更加通用和灵活的代码。
叶庭云
2024/05/25
3.7K0
Python魔法变量*args 和 **kwargs
多个实参,放到一个元组里面,以*开头,可以传多个参数;**是形参中按照关键字传值把多余的传值以字典的方式呈现 *args 和**kwargs只是一个通俗的命名约定,只有变量前面的 *(星号)才是必须的,也可写成*var 和**vars。 *args 和 **kwargs 主要用于函数定义。 可以将不定数量的参数传递给一个函数。主:不定的意思是预先并不知道, 函数使用者会传递多少个参数给你, 所以在这个场景下使用这两个关键字。 *args:(表示的就是将实参中按照位置传值,多出来的值都给args,且以元祖的方式呈现)
菲宇
2022/05/06
9400
python--一文搞懂参数args,kwargs
函数传参是最常用的方法,但是你真的掌握python里参数的传递和使用了吗?之前文章我们介绍了传参的拷贝情况,会不会引起传入参数的变化。本文详细介绍python的函数中*args, **kwargs的使用。
languageX
2023/04/03
7.9K2
Python中 *args 和 **kwargs 的含义?
答:在python中,*args和**kwargs通常使用在函数定义里。*args 和 **kwargs 都允许你给函数传不定数量的参数,即使在定义函数的时候不知道调用者会传递几个参数。ps: *args和**kwargs只是一个大家都遵守的习惯,名字可以任意写的 。
用户1564362
2019/11/12
1.3K0
RoboMaster SDK 解读.4
到目前为止我们遇到看第一个知识点,为什么要在这里设计一个这样玩的参数,一定是有原因的。┓( ´∀` )┏
云深无际
2021/03/12
6870
RoboMaster SDK 解读.4
Python函数参数传递机制
        最近在写代码的过程中,发现Python参数传递不是很明白。Python确实很灵活,但是灵活的后果就是要花更多的时间去研究。废话不多说,始めましょう!!!
py3study
2020/01/09
1.2K0
如何运用Python中函数的魔法参数,*args 和 **kwargs 真的很重要!!!
在Python中,*args 和 **kwargs 是用于函数定义中的特殊语法,它们允许函数接收可变数量的参数。*args 用于接收任意数量的位置参数(非关键字参数),而 **kwargs 用于接收任意数量的关键字参数。
小白的大数据之旅
2024/11/25
5400
如何运用Python中函数的魔法参数,*args 和 **kwargs 真的很重要!!!
[949]python不定长参数*args和**kwargs
在python语言写成的模块中的函数里,常常可以看到函数的参数表列里面有这两个参数,形如:
周小董
2021/03/08
3.7K1
Python基础-4 使用函数减少重复操作
记录日期、地点和消费内容及金额,这些内容会改变,我们把它们作为参数传递给函数((date, place, item, price)作为参数传入函数)。
一只大鸽子
2022/12/06
2.2K0
Python基础-4 使用函数减少重复操作
Python函数参数之全面讲解
Python函数参数 Python函数参数 本文主要介绍Python的函数参数,各种形式的参数。建议动手试试,可以加深理解。 函数参数 定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了。对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂的逻辑被封装起来,调用者无需了解。 Python的函数定义非常简单,但灵活度却非常大。除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以
1846122963
2018/03/09
1.4K0
python函数——形参中的:*args和**kwargs
多个实参,放到一个元组里面,以*开头,可以传多个参数;**是形参中按照关键字传值把多余的传值以字典的方式呈现
菲宇
2019/06/13
1.2K0
Python 拓展之 *args & **kwargs
我们在前几天的文章中写的函数,它们的参数的个数都是确定的,我们知道世界是不确定的,那么函数的参数当然也有不固定的时候,那么当我们碰到这个问题的时候,该怎么解决呢?请看接下来的文章。
编程文青李狗蛋
2019/11/07
5510
Python中函数参数传递方法*args, **kwargs,还有其他
本文将讨论Python的函数参数。我们将了解*args和**kwargs,/和*的都是什么,虽然这个问题是一个基本的python问题,但是在我们写代码时会经常遇到,比如timm中就大量使用了这样的参数传递方式。
自学气象人
2023/06/21
4350
Python中函数参数传递方法*args, **kwargs,还有其他
Python中函数参数传递方法*args, **kwargs,还有其他
来源:DeepHub IMBA本文约3000字,建议阅读9分钟本文将讨论Python的函数参数。 我们将了解*args和**kwargs,/和*的都是什么,虽然这个问题是一个基本的python问题,但是在我们写代码时会经常遇到,比如timm中就大量使用了这样的参数传递方式。 定义和传递参数 parameters 和arguments 之间的区别是什么?许多人交替使用这些术语,但它们是有区别的: Parameters 是函数定义中定义的名称; Arguments是传递给函数的值。 红色的是param
数据派THU
2023/04/18
1.2K0
Python中函数参数传递方法*args, **kwargs,还有其他
函数相关知识汇总
一.函数的定义 定义函数的规则: 1.定义:def 关键词开头,空格之后接函数名称和圆括号()。 2.参数:圆括号用来接收参数。若传入多个参数,参数之间用逗号分割。     参数可以定义多个,也可以不定义。     参数有很多种,如果涉及到多种参数的定义,应始终遵循位置参数、*args、默认参数、**kwargs顺序定义。     如上述定义过程中某参数类型缺省,其他参数依旧遵循上述排序 3.注释:函数的第一行语句应该添加注释。 4.函数体:函数内容以冒号起始,并且缩进。 5.返回值:return [表达式
用户1214487
2018/01/23
7870
python中*args和**kwargs的区别
*args是函数使用者可以发送任意数量非键值对的参数传给这个函数,*args在接收参数后,将返回值以元组tuple的形式返回。
用户7886150
2020/12/19
5210
python中*args和**kwargs用法解读
很多时候,会有人问到*args和**kwargs,那么如何理解呢?
雷子
2023/12/04
5100
python中*args和**kwargs用法解读
Python初学者应该了解的星号(*)
特别是星号(*),在Python中是一个用途广泛的操作符,而不仅仅用于两个数字相乘的运算之中。在本文中,我们将讨论星号的多种用途。
老齐
2020/05/15
1.1K0
Python初学者应该了解的星号(*)
软件测试|Python函数参数之必传参数、默认参数、可变参数、关键字参数的详细使用
在Python中,函数参数是定义在函数头部的变量,用于接收传递给函数的数据。Python函数参数有四种类型:必传参数、默认参数、可变参数和关键字参数。每种类型都有不同的使用方式和适用场景。本文将详细介绍这四种函数参数的使用方法。
霍格沃兹测试开发Muller老师
2023/10/13
1K0
推荐阅读
相关推荐
Python教程(25)——Python中参数类型详解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验