python 装饰器
一.装饰器概念与语法
python装饰器本质上就是一个嵌套函数,装饰器的返回值也是一个函数对象。简写:装饰器是以一个一函数为参数,返回值为函数的函数
语法:在需要装饰的类或者函数上面写@+函数名称。
二.装饰器的作用
装饰器可以在不更改原功能代码情况下,可以扩展新的功能。
开放封闭原则:
1.以实现的功能,不要去修改其内部(被装饰的函数或类)代码(封闭原则)
2.对功能的扩展(装饰器的扩展)是开放的(开放原则)
三.装饰器的方法
1.函数(闭包函数)
1)函数内部嵌套函数
2)外层函数的返回值是内层函数的函数名
3)内层嵌套函数对外层有一个非全局变量的引用
2.类装饰器(__call__)
1)__call __()方法是将实例成为一个可调用对象(即callable对象),同时不影响实例的构造,但可以改变实例的内部值。
四.代码演示
1.闭包形式的装饰器
1)闭包函数:符合上面三个条件
1 def func(): 2 a=10 3 def func_01(): 4 print(a) 5 return func_01()
2)装饰器:装饰函数
1 def func(fu): #外层函数的第一个参数类型为函数 2 def func_02(): 3 print("新功能") 4 fu() 5 return func_02 6 7 @func #func_1=func(func_1) 8 def func_1(): 9 print("已经实现的功能") 10 if "__name__" == "__main__": 11 func_1()
装饰器原理:
- 当@装饰器装饰的时候,会自动调用装饰器函数,然后把被装饰的函数当作参数传入进去,==》fu = func_1
- 装饰器的返回值,被原来被装饰的函数名接收。func_1 = func_02
调用被装饰的函数:
- 因为被装饰的函数指向的func_02,那么此时就是直接调用func_02,func_02内部又调用了fu(fu实际上此时的指向是被装饰的函数func_01)
流程:@func就相当于func(func_1),所以就是调用func()函数,然后return func_02(返回func_02也就是相当于调用func_02()),那么会先打印print("新功能"),然后接下来再调用fu()函数(也就是func_1()函数),然后就是打印print("已经实现的功能"),然后就结束了。
3)装饰器:装饰类
1 def func(fu): #外层函数的第一个参数类型为函数 2 def func_02(): 3 print("新功能") 4 return fu() #这里记得要加return ,要不然你下面 t=func_1() 返回就是一个None了,这里就是一个坑 5 return func_02 6 7 @func #func_1=func(func_1) 8 class func_1(): 9 def __init__(self): 10 print("已经实现的功能") 11 12 t=func_1() 13 print(t)
4)装饰器:带固定参装饰器
1 def func(fu): #外层函数的第一个参数类型为函数 2 def func_02(a,b): #这里记得也要传入参数,要不然会报错 3 print("新功能") 4 fu(a,b) #这里记得也要传入参数,要不然会报错 5 return func_02 6 7 @func #func_1=func(func_1) 8 def func_1(a,b): 9 print("a+b",a+b) 10 11 func_1(1,2)
5)装饰器:通用装饰器
1 def func(fu): #外层函数的第一个参数类型为函数 2 def func_02(*args,**kwargs): 3 print("新功能") 4 fu(*args,**kwargs) 5 return func_02 6 7 @func #func_1=func(func_1) 8 def func_1(): #你这里可以传入单个参数或者多个参数都可以 9 print("a+b") 10 11 func_1()
2.类装饰器(__call__)
1)类的装饰器写法, 不带参数(先通过构造函数__init __()传入函数;再通过__call __方法重载,并返回一个函数。)
1 class func_02(): 2 def __init__(self, func): 3 self.func = func 4 def __call__(self, *args, **kwargs): 5 print(‘{} is running‘.format(self.func.__name__)) 6 return self.func(*args, **kwargs) 7 8 @func_02 9 def func_1(): 10 print("运行成功") 11 12 func_1()
2)类的装饰器写法, 带参数(先通过构造函数__init __()传入装饰器参数;再通过__call __方法传入被装饰的函数,并返回一个函数)
1 class func_02(): 2 def __init__(self, code): 3 self.code = code 4 def __call__(self, func): 5 def func_03(*args, **kwargs): 6 print(‘{} is running‘.format(func.__name__)) 7 print(‘Code: {}‘.format(self.code)) 8 return func(*args, **kwargs) # 正式调用主要处理函数 9 return func_03 10 11 @func_02(code="123") #传入参数 12 def func_1(): 13 print("运行成功") 14 15 func_1()
五.面试问题
1.请列举装饰器两种实现方式 --------> 闭包函数、类中定义的__call__方法
2.装饰器可以装饰类吗 --------> 可以
3.类可以当装饰器吗 --------> 可以
4.如何实现通用装饰器 ---------> 传参使用不定长参数
5.可以同时被多个装饰器装饰吗 ---------> 可以
六.应用场景
1.可以再外层函数加上时间计算函数,计算函数运行时间。
2.计算函数运行次数。
3.可以用在框架的路由参数上。
4.插入日志,作为函数的运行日志。
5.事务处理,可以让函数实现事务的一致性,让函数要么一起运行成功,要么一起运行失败。
6.缓存,实现缓存处理。
7.权限的校验,在函数外层套上权限验证的代码,实现权限校验。
8.登录校验
1 def login(func): #外层函数的第一个参数类型为函数 2 def func_02(): 3 name=input("请输入用户名:") 4 pwd=input("请输入密码:") 5 if name=="admin" and pwd==1: 6 func() 7 else: 8 print("用户名或密码错误,请重新登录") 9 return func_02 10 11 @login #func_1=login(func_1) 12 def func_1(): 13 print("登录成功,欢迎您") 14 15 func_1()
原文:https://www.cnblogs.com/hao2018/p/11411555.html