装饰器的本质:一个闭包函数 装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展 装饰器的原则:开放封闭原则, 对扩展是开放的,对修改是封闭的
装饰器的固定格式
普通版
def timer(func): def inner(*args,kwargs): '''执行函数之前要做的''' re = func(*args,kwargs) '''执行函数之后要做的''' return re return inner
from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,kwargs): return func(*args,kwargs) return wrapper
装饰器的形成过程
import time def func1(func): #装饰器函数 def inner(): start = time.time() time.sleep(2) ret = func() #被装饰的函数 end = time.time() print(end - start) return ret return inner @func1 #语法糖 @装饰器函数名 def func2(): #被装饰的函数 time.sleep(3) print("nihao") func2()
完善一下上面那个装饰器
from functools import wraps def demo(func): @wraps(func) def wrapper(*args, kwargs): return func(*args, kwargs) return wrapper @demo def index(): ''' 小姐姐,我想你了! ''' print("hello,world") print(index.__doc__) print(index.__name__)
def outer(flag): def func1(func): def inner(*args, kwargs): if flag: print('''执行函数之前要做的''') ret = func(*args, kwargs) if flag: print('''执行函数之后要做的''') return ret return inner return func1 @outer(False) def func2(): time.sleep(3) print("nihao") func2()
多个装饰器装饰同一个函数
def wrapper1(func): def inner(): print('wrapper1 ,before func') func() print('wrapper1 ,after func') return inner def wrapper2(func): def inner(): print('wrapper2 ,before func') func() print('wrapper2 ,after func') return inner @wrapper2 @wrapper1 def f(): print('in f') f()
from functools import wraps def wrapper(func): @wraps(func) def inner(*args, kwargs): '''在函数被调用之前添加的代码''' ret = func(*args, kwargs) # func是被装饰的函数 在这里被调用 '''在函数被调用之后添加的代码''' return ret return inner # 使用 —— @wrapper @wrapper def func(): # inner pass func.__name__
带参数的装饰器
@wrapper -- > @warapper(argument) 三层嵌套函数 def outer(形参): def wrapper(func): def inner(*args,kwargs): '''在函数被调用之前添加的代码''' ret = func(*args,kwargs) # func是被装饰的函数 在这里被调用 '''在函数被调用之后添加的代码''' return ret return inner return wrapper @outer(True) def func(): pass
多个装饰器装饰一个函数
def wrapper1(func): @wraps(func) def inner(*args,kwargs): print('before 1') print('') ret = func(*args,kwargs) # func是被装饰的函数 在这里被调用 '''在函数被调用之后添加的代码''' return ret def wrapper2(func): @wraps(func) def inner(*args,kwargs): print('before 2') ret = func(*args,kwargs) # func是被装饰的函数 在这里被调用 '''在函数被调用之后添加的代码''' return ret @wrapper1 @wrapper2 def func(): print('111')
functools.wraps
from functools import wraps def wrapper(func): @wraps(func) def inner(*args, kwargs): print("在被装饰的函数执行之前做的事情") ret = func(*args, kwargs) print("再被装饰的函数执行之后做的事情") return ret return inner @wrapper def holiday(day): ''' 这是一个放假通知 ''' print("全体放假%s天" % day) return "好开心" print(holiday.__name__) print(holiday.__doc__) ret = holiday(3) print(ret)
带参数的装饰器
import time FLAGE = 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(FLAGE) #wahaha = timmer(wahaha) def wahaha(): time.sleep(0.1) print('wahahahahahaha') @timmer_out(FLAGE) def erguotou(): time.sleep(0.1) print('erguotoutoutou') wahaha() erguotou()
多个装饰器装饰一个函数
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())
def wrapper(func): #qqxing def inner(*args, kwargs): ret = func(*args, kwargs) #被装饰的函数 return ret return inner @wrapper #qqxing = wrapper(qqxing) def qqxing(): print(123) qqxing()
def qqxing(): ''' ni hao ,Bye ''' print("哈哈哈!") print(qqxing.__name__) #查看字符串格式的函数名 print(qqxing.__doc__) #查看document qqxing()
def wrapper(func): 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 '好开心' ret = holiday(3) print(ret)
def outer(*args): print(args) print(*args) def inner(*args): print('inner : ',args) inner(*args) outer(1,2,3,4) #==outer(*[1,2,3,4]) #==outer(*(1,2,3,4))
1.编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
FLAG = False def login(func): def inner(*args,kwargs): global FLAG '''登录程序''' if FLAG: ret = func(*args, kwargs) # func是被装饰的函数 return ret else: username = input('username : ') password = input('password : ') if username == 'boss_gold' and password == '22222': FLAG = True ret = func(*args,kwargs) #func是被装饰的函数 return ret else: print('登录失败') return inner @login def shoplist_add(): print('增加一件物品') @login def shoplist_del(): print('删除一件物品') shoplist_add() shoplist_del()
2.编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件
def log(func): def inner(*args,kwargs): with open('log','a',encoding='utf-8') as f: f.write(func.__name__+' ') ret = func(*args,kwargs) return ret return inner @log def shoplist_add(): print('增加一件物品') @log def shoplist_del(): print('删除一件物品') shoplist_add() shoplist_del() shoplist_del() shoplist_del() shoplist_del() shoplist_del()
import os from urllib.request import urlopen def cache(func): def inner(*args,kwargs): if os.path.getsize('web_cache'): with open('web_cache','rb') as f: return f.read() ret = func(*args,kwargs) #get() with open('web_cache','wb') as f: f.write(b'*'+ret) return ret return inner @cache def get(url): code = urlopen(url).read() return code # {'网址':"文件名"} ret = get('http://www.baidu.com') print(ret) ret = get('http://www.baidu.com') print(ret) ret = get('http://www.baidu.com') print(ret)