前置知识:
- python中函数调用时,传入的参数叫做实参,实参又分为位置参数(positional argument) 和关键字参数(keyword argument)。
位置参数
就是直接传值,按照其位置分配给函数定义中的形参,比如下面例子中函数调用时fun(1,2, c=5)中的1,2就是传入的位置参数。关键字参数
是按照函数定义中形参的名字来传值,比如 下面例子中函数调用时传入的 “c=5”就是关键字参数。 形参列表(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
- 在函数调用以及平时使用时, *用于将 tuple / list / str 解包(unpack),解包后的每个元素都作为单独的一个参数传入函数内部。见下面例子所示。
- 在函数定义时,*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
- 在函数调用时以及平常使用时, ** 用于将 dictionary字典 解包(unpack),然后将字典中的每一项作为单独的关键字参数传入函数内部。注意:字典中每一项的键值必须对应于函数定义中的形参名字
- 在函数定义时, **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()中