理解python中的'*','*args','**','**kwargs'

本文来源:http://blog.csdn.net/callinglove/article/details/45483097

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

1. 通过一个函数调用来理解’*’的作用
2. 通过一个函数的定义来理解’*args’的含义
3. 通过一个函数的调用来理解’**’的作用
4. 通过一个函数的定义来解’**kwargs’的含义
5.注意点:参数arg、*args、**kwargs三个参数的位置必须是一定的。必须是(arg,*args,**kwargs)这个顺序,否则程序会报错。
6. 通过一个应用实例来说明’args’,’kwargs’应用场景以及为何要使用它

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

def fun(a,b,c):
    print(a,b,c)
fun(1,2,3)  #1 2 3
l=[1,2,3]
fun(*l)   #1 2 3
l=(1,2,3)
fun(*l) #1 2 3 元组也可以
l=[1,2,3,4]
fun(*l)  #TypeError: fun() takes 3 positional arguments but 4 were given

‘*’ 做了什么?

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

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

数列’l’含有四个数值.因此,我们试图调用’fun(*l)’,’l’中数值拆开传给函数fun作为位置参数。

但是,’l’中有四个数值,调用’fun(*l)’相当于调用’fun(3,6,9,1)’,又因为函数’fun’定义中只用三个位置参数,因此我们得到这个错误。

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

def fun(*args):
    print(args,type(args))
fun(10)     #(10,) <class 'tuple'>
fun(10,20)  #(10,20) <class 'tuple'>
fun([1,2],20,[2,3])  #([1, 2],) <class 'tuple'>

#代码2 def fun(x,y,*args): print(x,y,args) fun(1,2,3,4,5) #1 2 (3, 4, 5)
#代码3
def fun(x,y,*args,z):
    print(x,y,args,z)
fun(1,2,3,4,5) #TypeError: fun() missing 1 required keyword-only argument: 'z'

可见:1、*args 用来将参数打包成tuple给函数体调用,参数个数不受限制,*args接收元组作为位置参数。

2、由代码2知:x为1,y为2,即第一个和第二个位置参数,之后只有一个参数*args,因此,*args接收除第一个和第二个参数之外的参数作为元组,即(3,4,5)。

3、由代码3知:位置参数z不能放置在*args之后

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

def fun(a,b,c):
    print(a,b,c)
fun(1,2,3)       #1 2 3
fun(a=1,b=2,c=3) #1 2 3
d={'b':2,'c':3}
fun(1,**d)       #1 2 3
dict={'b':2,'c':3}
fun(1,**dict)       #1 2 3
d={'a':1,'b':2,'c':3,'d':4}
fun(**d)    #TypeError: fun() got an unexpected keyword argument 'd'
d={'a':1,'b':2,'d':4}
fun(**d)    #TypeError: fun() got an unexpected keyword argument 'd'

在函数调用中使用”*”,我们需要元组;在函数调用中使用”**”,我们需要一个字典,字典中参数个数不能多,也不能少。

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

def fun(a,**kwargs):
    print(a,kwargs)
fun(1,b=2,c=3)           #1 {'b': 2, 'c': 3}
fun(1,**{'b':2,'c':3})   #1 {'b': 2, 'c': 3}
fun(1,{'b':2,'c':3})     #TypeError: fun() takes 1 positional argument but 2 were given

在函数定义中”**kwargs”意味着什么?
用”**kwargs”定义函数,kwargs接收除常规参数列表之外的键值参数字典,参数个数不固定,kwargs是个字典。

可以多传参数吗?因为参数不固定,所以也就没有多少的概念了。

5、注意点:参数arg、*args、**kwargs三个参数的位置必须是一定的。必须是(arg,*args,**kwargs)这个顺序,否则程序会报错。

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

class Model:
    def __init__(self,name):
        self.name=name
    def save(self,force_update=False,force_insert=False):
        if force_update and force_insert:
            raise ValueError('cannt perform both operations') #故意写作cannt而非cannot
        if force_update:
            print('updated an existing record')
        if force_insert:
            print('created a new record')

class Child(Model):
    def save(self,*args,**kwargs):
        if self.name=='abcd':
            super().save(*args,**kwargs)
            #super(Model,self).save(*args,**kwargs)
        else:
            return None
child=Child('abcd')
child.save(force_update=True)
child.save(force_insert=True)
child.save(force_insert=True,force_update=True)
# updated an existing record
# created a new record
# ValueError: cannt perform both operations

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

原文地址:https://www.cnblogs.com/bawu/p/8243108.html