python_闭包_装饰器
闭包
装饰器
# 装饰器形成的过程 : 最简单的装饰器 有返回值得 有一个参数 万能参数
# 装饰器的作用
# 原则 :开放封闭原则
# 语法糖:@装饰函数名
# 装饰器的固定模式
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__+'\n') 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)