python中*args与**kwarsg及闭包和装饰器的用法
作者:zew1040994588
*args与**kwarsg及闭包和装饰器
过程
先理解闭包,再理解装饰器,不要忘了不定长参数
def func(): msg = '111' def func1(): print(msg) return func1 """ 1-理解闭包 闭包即内部函数调用外部函数作用域里面的变量 比如func1就是一个闭包函数 """ func()()# 这里实际上是func1()
""" 2-装饰器 fn是被装饰的目标函数 2.1-仅仅只是传递函数名的装饰器[基本不会用到] 2.2-装饰带有参数的函数 2.3-装饰带有返回值的函数 2.4-装饰参数不确定的函数[可归类到装饰带有参数的函数里面] 2.5-装饰器本身携带参数 """
def decorator(fn): def wrapper(): print("添加的功能,装饰不带有参数的函数") return fn() return wrapper @decorator def test(): print("原有功能") test()# 实际上是decorator(test) def decorator1(fn): def wrapper(n1,n2): print("添加的功能,装饰带有参数的函数") return fn(n1,n2) return wrapper @decorator1 def test1(a,b): print("a+b=%s"%(a+b)) print("原有功能") test1(1,2)# 实际上是decorator1(test1(1,2)) def decoretor2(fn): def wrapper(): print("添加的功能,装饰带有返回值的函数") res = fn() return res return wrapper @decoretor2 def test2(): print("原有功能") return "返回值001" a = test2() # 实际是decorator2(test2) print(a) def decorator3(fn): def warpper(*args,**kwargs): print("添加的功能,装饰不定长参数的函数") return fn(*args,**kwargs) return warpper @decorator3 def test3(n1,n2,n3): print("原有功能") print(n1+n2+n3) test3(1,2,3)# 实际上是decorator1(test1(1,2,3)) def decorator4(home): def func_1(fn): def wrapper(*args,**kwargs): print("装饰器本身携带参数") print("目前家在%s"%(home)) return fn(*args,**kwargs) return wrapper return func_1 @decorator4(home='wuhan') def test4(n1,n2,n3): print("原有功能") print(n1+n2+n3) # test3(1,2,3)=decorator3(home="武汉")(test(1,2,3))() """ 1-先调用decorator3(home="wuhan") 2-执行func_1(test(1,2,3)) # 到这里其实就和前面的装饰器一样 3-执行wrapper 4-执行test(1,2,3) """ test4(1,2,3)
Python fun(*args,**kwargs)中*args,**kwargs参数含义及用法
1. Python函数中的两种参数
我们知道,在Python中有两种参数
- 位置参数(positional argument): 位置参数只能由参数位置决定
- 关键词参数(keyword argument): 关键词参数只需要用 keyword = somekey 的方法即可传参
位置参数只能由参数位置决定。这也就决定了位置参数一定要在前面,否则关键词参数数量的变化都会使得位置无法判断。
2. 理解函数调用中的*
*的作用是将tuple或者list中的元素进行unpack,分开传入,作为多个参数。
def func(a,b,c) print(a,b,c) alist = [1,2,3] # 这里alist的长度必须和函数中参数的个数相同,否则会报错 func(*alist) # 等同于 func(1, 2, 3) 1 2 3
2.1 * 做了什么
它拆开数列alist的数值作为位置参数,并把这些位置参数传给函数func来调用。
因此拆数列、传位置参数意味着func(*alist)与func(1,2,3)是等效的,因为 alist= [1,2,3]。
3. 理解函数调用中的**
**的作用是unpack字典,并将字典中的数据项作为键值参数传给函数。
为了更好的理解举几个例子:
def func(a, b, c): print(a, b, c) if __name__ == "__main__": dic = {'b': 2, 'c': 3} func(1, b=2, c=3) func(1, **dic) 1 2 3 1 2 3
4. 理解函数调用中的*args和**kwargs
kwargs是keyword argument的缩写,args就是argument。常见的是*args 在 **kwargs 前面。
这两个的用途和效果如下:
def this_fun(a,b,*args,**kwargs): """ 在这个函数定义中,参数”a, b”代表”常规参数列表”。 args 接收元组作为位置参数,而非是常见的参数列表 """ print(a,b) print(args) print(kwargs) if __name__ = '__main__' this_fun(0,1,2,3,index1=11,index2=22) 0,1 (2, 3) {'index2': 22, 'index1': 11}
也就是说,第一中不定的参数形式把剩下的没有关键字的参数收起来形成一个tuple,而第二种把有关键字的收起来做成一个字典。
5. 实例说明args, kwargs的应用场景
5.1 子类传参给父类方法
在任何时候继承类和重写方法的,我们应当用到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: print("Updated an existing record") if force_insert: print("Created a new record")
定义一个类,我们可以创建类的对象,类的对象有一个方法save().假设类的对象可以通过save()方法保存到数据库中。通过函数save()参数来决定是否在数据库中创建一条记录或者更新现存的记录。
构造一个新类,类有Model的行为,但只有符合某些条件才会保存这个类的对象。这个新类继承Model,重写Model的save()
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实体并调用save方法:
c=ChildModel('abcd') c.save(force_insert=True) c.save(force_update=True) # 结果 Created a new record Updated an existing record
这里传参数给对象的save()方法。调用的是子类的save(), 它接收一个包含关键字参数kwargs的字典。然后,它使用**将字典作为关键字参数unpack,然后将其传递给超类save()。因此,超类save()获得关键字参数force_insert并执行相应的操作。
5.2 *args 实现sum
def my_sum(*args): res = 0 for val in args: res += val return res l1 = [4, 8] l2 = [1,2,3] print(my_sum(*l1)) # 12 print(my_sum(*l2)) # 6 print(my_sum(4,5,6)) # 15
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。