# 装饰器形成的过程 : 最简单的装饰器 有返回值得 有一个参数 万能参数
# 装饰器的作用
# 原则 :开放封闭原则
# 语法糖:@装饰函数名
# 装饰器的固定模式
import time # time.time() # 获取当前时间 # time.sleep() # 等待 # 装饰带参数的装饰器 def timer(f): # 装饰函数def inner(*args,**kwargs):start = time.time()ret = f(*args,**kwargs) # 被装饰函数end = time.time()print(end-start)return retreturn inner @timer # 语法糖 @装饰器函数名 在被装饰函数的上面 def func(a): # 被装饰的函数time.sleep(0.1)print('哈哈哈')return 'hello'# func = timer() ret = func() # inner print(ret)
# 装饰器的作用 不想修改函数的调用方式 但是还想再原来的函数前后添加功能
# timmer 就是一个装饰函数,只是对一个函数 有一些装饰作用
# 原则:开放封闭原则
# 开放:对扩展是开放的
# 封闭:对修改是封闭的
# 装饰器的固定模式
def wrapper(f): # 装饰器函数,f是被装饰的函数def inner(*args,**kwargs):'''在被装饰函数之前要做的事'''ret = f(*args,**kwargs) # 被装饰的函数'''在被装饰函数之后要做的事'''return retreturn inner@wrapper # func_name = wrapper(func_name) def func_name():print(123)ret = func_name
装饰器的进阶
# functools.wraps
# 带参数的装饰器
# 多个装饰器装饰同一个函数
wrapsdef wahaha():'''打印这个函数'''pass print(wahaha.__name__) # 查看字符串格式函数名 print(wahaha.__doc__) # 查看函数注释from functools import wraps # 引入wraps,全局被装饰的函数也能使用 def wrapper(f):@wraps(f) # 在这里装饰inner 作用保留原有函数的名称和docstringdef inner(*args,**kwargs):'''在被装饰函数之前要做的事'''ret = f(*args,**kwargs)'''在被装饰函数之后要做的事'''return retreturn inner@wrapper # func_name = wrapper(func_name) def func_name():print(123)ret = func_nameprint(func_name.__name__)
# 带参数的装饰器
import time # 引入时间模块 flage = False # 定义一个全局变量 def timer_out(flage): 装饰器函数外面在裹一个函数def timer(func):def inner(*args,**kwargs):if flage: # 加个判断start = time.time()ret = func(*args,**kwargs)end = time.time()print(end-start)return retelse:ret = func(*args,**kwargs)return retreturn innerreturn timer@timer_out(flage) #这里要明白 timer_out(flage) = timer ,所以还是@timer def wahaha():time.sleep(0.1)print('hehei')@timer_out(flage) def hel():time.sleep(0.1)print('lalala')wahaha() hel()
# 多个装饰器装饰一个函数
def wrapper1(func):def inner1():print('wrapperl,before func')func()print('wrapper1 after func')return inner1def wrapper2(func):def inner2():print('wrapper2,before func')func()print('wrapper2 after func')return inner2@wrapper1 @wrapper2 #距离最近的先执行,这个要好好理解执行变化 def f():print('in f') f()
# 1.编写装饰器,为多个函数加上认证的功能(用户的账户密码来源于文件)要求登录成功一次,后续的函数都无需再输入用户名和密码
flat = False #定义一个全局变量 好像其他也能代替 def login(func):def inner(*args,**kwargs):global flat # 这里不能用nonlocal声明'''先登录程序'''if flat:ret = func(*args,**kwargs)return retelse:username = input('username:')password = input('password:')if username == 'boss' and password == '666666':flat = Trueret = func(*args,**kwargs)return retelse: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__+'\n')ret = func(*args,**kwargs)return retreturn inner@log def shoplist_add():print('增加一件物品') @log def shoplist_del():print('删除一件物品')
# 进阶作业(选做)
# 1.编写下载网页内容的函数,要求功能是:用户传入一个URL,函数返回下载页面的结果
from urllib.request import urlopen def get(url):code = urlopen(url).readreturn code ret =get('http://www.baidu.com') print(ret)
#2.为题目1编写装饰器,实现缓存网页内容的功能:
# 具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则就去下载然后
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)with open('web_cache','wb') as f:f.write(ret)return retreturn inner@cache def get(url):code = urlopen(url).read()return coderet = get('http://www.baidu.com') print(ret)