# 装饰器形成的过程 : 最简单的装饰器 有返回值得 有一个参数 万能参数
# 装饰器的作用
# 原则 :开放封闭原则
# 语法糖:@装饰函数名
# 装饰器的固定模式
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 ret
return 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 ret
return inner
@wrapper # func_name = wrapper(func_name)
def func_name():
print(123)
ret = func_name
装饰器的进阶
# functools.wraps
# 带参数的装饰器
# 多个装饰器装饰同一个函数
wraps
def wahaha():
'''打印这个函数'''
pass
print(wahaha.__name__) # 查看字符串格式函数名
print(wahaha.__doc__) # 查看函数注释
from functools import wraps # 引入wraps,全局被装饰的函数也能使用
def wrapper(f):
@wraps(f) # 在这里装饰inner 作用保留原有函数的名称和docstring
def inner(*args,**kwargs):
'''在被装饰函数之前要做的事'''
ret = f(*args,**kwargs)
'''在被装饰函数之后要做的事'''
return ret
return inner
@wrapper # func_name = wrapper(func_name)
def func_name():
print(123)
ret = func_name
print(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 ret
else:
ret = func(*args,**kwargs)
return ret
return inner
return 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 inner1
def 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 ret
else:
username = input('username:')
password = input('password:')
if username == 'boss' and password == '666666':
flat = True
ret = func(*args,**kwargs)
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('删除一件物品')
# 进阶作业(选做)
# 1.编写下载网页内容的函数,要求功能是:用户传入一个URL,函数返回下载页面的结果
from urllib.request import urlopen
def get(url):
code = urlopen(url).read
return 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 ret
return inner
@cache
def get(url):
code = urlopen(url).read()
return code
ret = get('http://www.baidu.com')
print(ret)