装饰器
装饰器的主要功能:
在不改变函数调用方式的基础上在函数的前、后添加功能。
装饰器的固定格式:
#装饰器的本质 :闭包函数
#功能:就是在不改变原函数调用方式的情况下,在这个函数前后加上扩展功能
def timmer(func):
def inner(*args,**kwargs):
'''添加函数调用之前的扩展代码'''
ret = func(*args,**kwargs)
'''添加函数调用之后的扩展代码'''
return ret
return inner
语法:在被装饰对象的正上方的单独一行,使用@语法糖可以直接调用函数装饰器
设计模式
原则 开放封闭原则
#对扩展是开放的
#对修改是封闭的
1.对扩展是开放的
为什么要对扩展开放呢?
我们必须允许代码扩展、添加新功能。
2.对修改是封闭的
为什么要对修改封闭呢?
我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
import time
def wrapper(func): # 装饰
def inner(*args, **kwargs):
start = time.time()
ret = func(*args, **kwargs)
end = time.time()
print(end - start)
return ret
return inner
@wrapper
def lll():
time.sleep(0.1)
print('hello')
lll()
编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
login_dic={
"name":"None",
"passwd":"None",
}
with open('passwd.txt', 'r+', encoding='utf-8') as f1:
f2 = eval(f1.read())
def login(func):
def inner(*args, **kwargs):
'''判断用户名、密码是否在字典中'''
if login_dic["name"]==f2["name"] and login_dic["passwd"]==f2["passwd"]:
ret = func(*args, **kwargs)
return ret
else:
name = input("请输入用户名:")
passwd = input("请输入密码:")
if name == f2['name'] and passwd == f2['passwd']:
print("登陆成功")
login_dic['name'] = name
login_dic['passwd'] = passwd
ret = func(*args, **kwargs)
return ret
else:
print("输入有误,请重新输入")
return inner
@login
def fun():
print("123")
print("456")
fun()
@login
def check():
print("789")
带参数的装饰器
def timer(func):
def inner(a):
start = time.time()
func(a)
print(time.time() - start)
return inner
@timer
def func1(a):
print(a)
func1(1)
装饰器——带参数的装饰器
import time
def timer(func):
def inner(*args,**kwargs):
start = time.time()
re = func(*args,**kwargs)
print(time.time() - start)
return re
return inner
@timer #==> func1 = timer(func1)
def func1(a,b):
print('in func1')
@timer #==> func2 = timer(func2)
def func2(a):
print('in func2 and get a:%s'%(a))
return 'fun2 over'
func1('aaaaaa','bbbbbb')
print(func2('aaaaaa'))
装饰器——成功hold住所有函数传参
import time
def timer(func):
def inner(*args,**kwargs):
start = time.time()
re = func(*args,**kwargs)
print(time.time() - start)
return re
return inner
@timer #==> func2 = timer(func2)
def func2(a):
print('in func2 and get a:%s'%(a))
return 'fun2 over'
func2('aaaaaa','bbbbbb')
print(func2('aaaaaa'))
装饰器——带返回值的装饰器
def outer(flag):
def timer(func):
def inner(*args,**kwargs):
if flag:
print('''执行函数之前要做的''')
re = func(*args,**kwargs)
if flag:
print('''执行函数之后要做的''')
return re
return inner
return timer
@outer(False)
def func():
print(111)
func()
带参数的装饰器格式
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()
多个装饰器装饰同一个函数
实例
#带参数的装饰器 开关
# F = True
F = False
def outer(flag):
def wrapper(func):
def inner(*args,**kwargs):
if flag:
print('before')
ret = func(*args,**kwargs)
print('after')
else:
ret = func(*args, **kwargs)
return ret
return inner
return wrapper
@outer(F) #-->@wrapper -->hahaha = wrapper(hahaha) #-->hahaha == inner
def hahaha():
print('hahaha')
@outer(F) #shuangww = outer(shuangww)
def shuangww():
print('shuangwaiwai')
shuangww()
hahaha()
'''
1.编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
2.编写装饰器,实现缓存网页内容的功能:
具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),
就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
'''
url_l = []
from urllib.request import urlopen
def get_cache(func):
def inner(*args,**kwargs):
url = args[0]
filename = str(hash(url))
if url in url_l:
f = open(filename,'rb')
ret = f.read()
else:
url_l.append(url)
ret = func(*args, **kwargs)
f = open(filename,'wb')
f.write(ret)
f.close()
return ret
return inner
@get_cache
def get(url):
return urlopen(url).read()
print(get(''))
print(get(''))
print(get(''))
print(get(''))
print(get(''))