装饰器
2019-08-14 17:25 美丽的名字 阅读(86) 评论(0) 收藏 举报装饰器
定义:本质就是函数,从来未其他函数增加附件功能。
原则:不修改被修饰函数的源代码,不修改被修饰函数的调用方式
装饰器 = 高阶函数 + 函数嵌套 + 闭包
高阶函数:
- 函数接收的参数是一个函数名
- 函数的返回值是一个函数名
- 满足上述条件中的任一个都可称之为高阶函数
函数嵌套:
- 在函数中定义另一个函数,并进行调用
def f1(): def f2(): def f3(): print('from f3') f3() f2()
注:print(locals())获取当前的环境变量,当前没有定义该环境变量,会逐层网上找,直到找到为止,否则报错。
闭包:
#内部函数包含对外部作用域而非全局作用域的引用
def counter(): n=0 def incr(): nonlocal n x=n n+=1 return x return incr c=counter() print(c()) print(c()) print(c()) print(c.__closure__[0].cell_contents) #查看闭包的元素
装饰器样例一:
import time def timer(func): def wrapper(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) stop_time = time.time() print("time period: %s" % (stop_time - start_time)) return res return wrapper @timer def test(): time.sleep(2) print("running in test....") return "return from test" test()
有参装饰器样例二:
def auth(driver='file'): def auth2(func): def wrapper(*args,**kwargs): name=input("user: ") pwd=input("pwd: ") if driver == 'file': if name == 'egon' and pwd == '123': print('login successful') res=func(*args,**kwargs) return res elif driver == 'ldap': print('ldap') return wrapper return auth2 @auth(driver='file') def foo(name): print(name) foo('egon')
装饰器的副作用:
Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。写一个decorator的时候,最好在实现之前加上functools的wrap,它能保留原有函数的名称和docstring
没有加wraps的情况:
#coding=utf-8 # -*- coding=utf-8 -*- from functools import wraps def my_decorator(func): def wrapper(*args, **kwargs): '''decorator''' print('Calling decorated function...') return func(*args, **kwargs) return wrapper @my_decorator def example(): """Docstring""" print('Called example function') print(example.__name__, example.__doc__)
执行结果:
('wrapper', 'decorator')
添加wraps后的情况:
#coding=utf-8 # -*- coding=utf-8 -*- from functools import wraps def my_decorator(func): @wraps(func) def wrapper(*args, **kwargs): '''decorator''' print('Calling decorated function...') return func(*args, **kwargs) return wrapper @my_decorator def example(): """Docstring""" print('Called example function') print(example.__name__, example.__doc__)
执行结果:
('example', 'Docstring')
多个装饰器叠加:
# 叠加多个装饰器 # 1. 加载顺序(outter函数的调用顺序):自下而上 # 2. 执行顺序(wrapper函数的执行顺序):自上而下
def outter1(func1): #func1=wrapper2的内存地址 print('加载了outter1') def wrapper1(*args,**kwargs): print('执行了wrapper1') res1=func1(*args,**kwargs) return res1 return wrapper1 def outter2(func2): #func2=wrapper3的内存地址 print('加载了outter2') def wrapper2(*args,**kwargs): print('执行了wrapper2') res2=func2(*args,**kwargs) return res2 return wrapper2 def outter3(func3): # func3=最原始的那个index的内存地址 print('加载了outter3') def wrapper3(*args,**kwargs): print('执行了wrapper3') res3=func3(*args,**kwargs) return res3 return wrapper3 @outter1 # outter1(wrapper2的内存地址)======>index=wrapper1的内存地址 @outter2 # outter2(wrapper3的内存地址)======>wrapper2的内存地址 @outter3 # outter3(最原始的那个index的内存地址)===>wrapper3的内存地址 def index(): print('from index') print('======================================================') index() 示范代码
浙公网安备 33010602011771号