# 装饰器的作用 —— 不想修改函数的调用方式 但是还想在原来的函数前后添加功能
# 原则: 开放封闭原则
# 开放 : 对扩展是开放的
# 封闭 : 对修改是封闭的
# 语法糖 :@
import time def timmer(f): # 装饰器函数 def inner(): start = time.time() ret = f() # 被装饰的函数 end = time.time() print(end - start) return ret return inner @timmer # 语法糖 @装饰器函数名 def func(): # 被装饰的函数 time.sleep(0.01) print('老板好同事好大家好') return '新年好' ret = func() # inner() print(ret) ''' 老板好同事好大家好 0.010040044784545898 新年好 '''
# 修饰带参数函数的装饰器
def wrapper(func): #qqxing def inner(*args, **kwargs): ret = func(*args, **kwargs) # 被装饰的函数 return ret return inner @wrapper # qqxing = wrapper(qqxing) def qqxing(a, b): print('{} {}'.format(a, b)) ret = qqxing(1, {'2': 'hello'}) # inner ''' 1 {'2': 'hello'} '''
# functools wraps用法
from functools import wraps def wrapper(func): # func = holiday @wraps(func) # 如果不加上wraps语法糖,对于整一个代码来说,holiday函数并不存在了,有的只是被inner函数装饰之后的holiday def inner(*args, **kwargs): print('在被装饰的函数执行之前做的事') ret = func(*args,**kwargs) print('在被装饰的函数执行之后做的事') return ret return inner @wrapper # holiday = wrapper(holiday) def holiday(day): '''这是一个放假通知''' print('全体放假%s天' % day) return '好开心' print('holiday()的名字:', holiday.__name__) print('holiday()的注释:', holiday.__doc__) ret = holiday(3) # inner print(ret) '''不加@wraps(func) holiday()的名字: inner holiday()的注释: None 在被装饰的函数执行之前做的事 全体放假3天 在被装饰的函数执行之后做的事 好开心 ''' '''加上@wraps(func) holiday()的名字: holiday holiday()的注释: 这是一个放假通知 在被装饰的函数执行之前做的事 全体放假3天 在被装饰的函数执行之后做的事 好开心 '''
# 装饰器传参数
# 如果有500个函数用过一次装饰器了,然后我不想它们走装饰器了,这时候就需要把语法糖给去掉。一个个删除语法糖也要删除500次,过于麻烦,所以就选择在原装饰器外部再加一层用于接收FLAG参数 import time FLAG = False def timmer_out(flag): def timmer(func): def inner(*args,**kwargs): if flag: start = time.time() ret = func(*args,**kwargs) end = time.time() print(end-start) return ret else: ret = func(*args, **kwargs) return ret return inner return timmer # timmer = timmer_out(FLAGE) @timmer_out(FLAG) #wahaha = timmer(wahaha) def wahaha(): time.sleep(0.1) print('wahahahahahaha') @timmer_out(FLAG) def erguotou(): time.sleep(0.1) print('erguotoutoutou') wahaha() erguotou() '''FLAGE = True时 wahahahahahaha 0.10003066062927246 erguotoutoutou 0.10085654258728027 ''' '''FLAGE = False时 wahahahahahaha erguotoutoutou '''
# 多个装饰器装饰一个函数
def wrapper1(func): def inner1(): print('wrapper1 ,before func') ret = func() print('wrapper1 ,after func') return ret return inner1 def wrapper2(func): def inner2(): print('wrapper2 ,before func') ret = func() print('wrapper2 ,after func') return ret return inner2 def wrapper3(func): def inner3(): print('wrapper3 ,before func') ret = func() print('wrapper3 ,after func') return ret return inner3 @wrapper3 @wrapper2 @wrapper1 def f(): print('in f') return '哈哈哈' print(f()) ''' wrapper3 ,before func wrapper2 ,before func wrapper1 ,before func in f wrapper1 ,after func wrapper2 ,after func wrapper3 ,after func 哈哈哈 '''
装饰器题目
# 1、编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
FLAG = False def login(f): def inner(): global FLAG if FLAG: ret = f() else: username = input('Please input your username:') password = input('Please input your password:') with open('login.txt', 'r') as fr: a, b = fr.read().split(' ') if username == a and password == b: FLAG = True ret = f() return ret else: print('username or password error!') return return inner @login def shoplist_add(): print('add...') @login def shoplist_del(): print('del...') shoplist_add() shoplist_del() ''' Please input your username:admin Please input your password:123 add... del... '''
# 2、编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件
import datetime def outer(f): def inner(): with open('log.txt', 'a+') as fw: time = datetime.datetime.now() fw.write('{0}\t{1}\n'.format(time, f.__name__)) fw.close() ret = f() return ret return inner @outer def func1(): print('func1') @outer def func2(): print('func2') func1() func2()