【Python】python中 *、*args 、 **、 **kwargs用法详解

前置知识:

  1. python中函数调用时,传入的参数叫做实参,实参又分为位置参数(positional argument)关键字参数(keyword argument)位置参数就是直接传值,按照其位置分配给函数定义中的形参,比如下面例子中函数调用时fun(1,2, c=5)中的1,2就是传入的位置参数。关键字参数是按照函数定义中形参的名字来传值,比如 下面例子中函数调用时传入的 “c=5”就是关键字参数。
  2. 形参列表(formal parameter list)形参是指在函数定义时设置的参数,以下面函数定义为例, [a , b, c] 就是形参列表
>>>def fun(a, b, c, *args, **kwargs):
>>>	    print(a,b,c)
>>>	    print(args)
>>>	    print(kwargs)

>>>fun(1,2,c=3)
''' 
1 2 3
()
{}
'''

* 与 *args

  1. 在函数调用以及平时使用时, *用于将 tuple / list / str 解包(unpack),解包后的每个元素都作为单独的一个参数传入函数内部。见下面例子所示。
  2. 在函数定义时,*args的作用就是将未来被调用时多传进来的位置参数打包成一个名为args的元组,在函数内部使用。 本质的操作应该是:“ * args = 多余的位置参数”,*又具有解包的功能,这样就实现了将多余的位置参数放置在了args这个包中。以本文中fun函数的定义为例, 见如下代码所示。
>>>	fun(1,2,3,4,5)
'''
1 2 3
(4, 5)
{}
'''
>>>	d = (2,3)
>>>	print(*d)
''' 2 3 '''
>>>	fun(1,*d)
'''
1 2 3
()
{}
'''
>>>	fun(1,2,*d)
'''
1 2 2
(3,)
{}
'''

** 和 **kwargs

  1. 在函数调用时以及平常使用时, ** 用于将 dictionary字典 解包(unpack),然后将字典中的每一项作为单独的关键字参数传入函数内部。注意:字典中每一项的键值必须对应于函数定义中的形参名字
  2. 在函数定义时, **kwargs用于接受在调用时超过形参列表数量的所有关键字参数,并将他们打包成一个字典 kwargs传入函数内部使用,具体的过程与*args相似。同样以fun函数为例来分析,见如下代码。
>>> e ={"b":2,"c":3}
>>> fun(1,**e)
'''
1 2 3
()
{}
'''
>>>	f = {"c": 2, "d": 3}
>>>	fun(1, 2, **f)
''' 2 3 '''
>>>	fun(1,*d)
'''
1 2 2
()
{'d': 3}
'''

代码案例

当我们继承一个类并覆盖继承类的某些方法时,我们应该使用 *args 和 **kwargs 并将接收到的位置和关键字参数传递给父类方法。

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:
            #Update an existing record
            print("Updated an existing record")
        if force_insert:
            #Create a new record
            print("Created a new record")

class ChildModel(Model):
    def save(self, *args, **kwargs):
        if self.name == "abcd":
            # 下面这句是python2的写法,在python3中可直接写成:super.save(*args, **kwargs)
            super(ChildModel, self).save(*args, **kwargs)
        else:
            return None       

这里创建了两个类,一个父类 Model,一个子类 ChildModel 继承 Model。因此,我们需要从ChildModel的save()方法中调用父类的“ save()”方法。另外,子类的()方法,即ChildModel中的save()应该能够接受Model中save()接受的任何参数,并且必须将这些参数传递给父类Model的 save()中。因此,我们在子类 save()方法的参数列表中有 *args和 **kwargs,以接收形参列表以外的任何位置参数或关键字参数。

>>> c=ChildModel('abcd')
>>> c.save(force_insert=True)
'''Updated an existing record'''

首先创建一个 ChildModel 类对象 c,名字为 “abcd"。c.save()是调用ChildModel类的save()方法,将force_insert=True 打包成一个字典kwargs,因为名字==“abcd",所以 执行super(ChildModel, self).save(*args, ** kwargs)。 首先通过super(ChildModel, self)找到ChildModel的父类Model,然后使用.save(*args, **kwargs)调用父类中的save方法,这里面的 * 和 ** 是用来解包的,**将字典kwargs解包成一个个的关键字参数,传入进父类的save()中

参考:Understanding ‘*’, ‘*args’, ‘**’ and ‘**kwargs’

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值