装饰器
- 一:编写函数,(函数执行时间用time.sleep(n)代表)
- 二:编写装饰器,为函数加上统计时间的功能
- 三:编写装饰器,为函数加上认证的功能
- 四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
- 注意:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式
- 五:编写装饰器,为多个函数加上认证功能,要求登录成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录
- 六:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
- 七:为题目五编写装饰器,实现缓存网页内容的功能:
- 具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
- 扩展功能:用户可以选择缓存介质/缓存引擎,针对不同的url,缓存到不同的文件中
- 八:还记得我们用函数对象的概念,制作一个函数字典的操作吗,来来来,我们有更高大上的做法,在文件开头声明一个空字典,然后在每个函数前加上装饰器,完成自动添加到字典的操作
- 九 编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017-07-21 11:12:11 f1 run写入到日志文件中,日志文件路径可以指定
一:编写函数,(函数执行时间用time.sleep(n)代表)
import time
def home(n):
time.sleep(n)
print('welcome to home page')
二:编写装饰器,为函数加上统计时间的功能
def timmer(func):
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print(stop_time-start_time)
return res
return wrapper
三:编写装饰器,为函数加上认证的功能
认证文件来源
def outter(engine='file'):
def deco2(func2):
def wrapper2(*args,**kwargs):
name=input('username>>>: ').strip()
pwd=input('password>>>: ').strip()
if engine == 'file':
print('基于file的认证')
if name == 'juanfu' and pwd == '123':
print('login successful')
res2=func2(*args,**kwargs)
return res2
else:
print('username or password error')
elif engine == 'mysql':
print('基于mysql的认证')
elif engine == 'ldap':
print('基于ldap的认证')
else:
print('未知的engine')
return wrapper2
return deco2
@outter(engine='mysql') # @deco2 # index=deco2(index)
def index(x,y):
print('index=>',x,y)
index(1,2) # index=>wrapper
角色认证
def auth(role):
def wrapper(func): # 被装饰的函数对象
def inner(*args, **kwargs): # 被装饰的函数对象的参数: 可能有,也可能没有
# 调用被装饰对象前添加的功能可以在此处写
# 调用前添加认证
if role == '销售部':
res = func(*args, **kwargs) # timer()
# 调用被装饰对象后添加的功能可以在此处写
return res
elif role == '技术能力有限部门':
res = func(*args, **kwargs) # timer()
# 调用被装饰对象后添加的功能可以在此处写
return res
else:
print('该用户没有权限...')
return inner
return wrapper
@auth('vip')
def index():
pass
四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
注意:从文件中读出字符串形式的字典,可以用eval(’{“name”:“egon”,“password”:“123”}’)转成字典格式
方式一:
login=False
def auth(func):
def wrapper(*args,**kwargs):
global login
if login :
res = func(*args, **kwargs)
return res
else:
while True:
username=input('请输入用户名: ').strip()
pwd=input('请输入用户名: ').strip()
with open('user.txt','r',encoding='utf-8')as f:
dic=f.read()
eval(dic)
if username in dic and pwd in dic:
print('登录成功')
login=True
res=func(*args,**kwargs)
return res
else:
print('用户名或密码错误')
return wrapper
@auth
def home(n):
global login
time.sleep(n)
print('welcome to home page')
home(1)
@auth
def index():
global login
print('====>from index')
index()
方式二:
# 1) 先将user.txt文件中的数据读取出来,把 str 转换成 dict 类型
with open('user.txt', 'r', encoding='utf-8') as f:
# 从文件中读取出来的都是字符串
user_data = f.read()
# print(user_data, type(user_data))
# 通过eval内置函数,将str ---> dict 类型
# eval,可以将字符串转行成python中对应的数据类型;
user_dict = eval(user_data)
# print(user_dict, type(user_dict))
# 用于记录是否有用户登录
user_login = {'user': None}
# 注意(涨知识):
# 在函数内部引用全局变量时,可变类型不需要global,不可变类型需要使用global
# 登录功能
def login():
while True:
username = input('请输入用户名: ').strip()
password = input('请输入密码: ').strip()
if username == user_dict.get('name') and password == user_dict.get('password'):
# 登录成功后,必须记录用户登录状态
# 将user_login全局变量,引用到函数内部来修改
user_login['user'] = username
print('login successful!')
break
else:
print('登录失败!')
# 2) 登录认证装饰器编写
def login_auth(func): # 被装饰的函数对象
def inner(*args, **kwargs): # 被装饰的函数对象的参数: 可能有,也可能没有
# 用户登录认证的逻辑
if user_login.get('user'):
res = func(*args, **kwargs)
# 调用被装饰对象后添加的功能可以在此处写
return res
else:
# 调用登录功能,让用户去登录
login()
res = func(*args, **kwargs)
return res
return inner
@login_auth
def pay():
print('pay...')
@login_auth
def transfer():
print('transfer...')
pay()
import time
time.sleep(1)
transfer()
五:编写装饰器,为多个函数加上认证功能,要求登录成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录
方式一:
import time
import random
user={'user':None,'login_time':None,'timeout':0.0005}
def timmer():
def wrapper():
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print(stop_time-start_time)
return res
return wrapper
def auth(func):
def wrapper(*args,**kwargs):
if user['user']:
timeout=time.time()-user['login_time']
if timeout < user['timeout']:
return func(*args,**kwargs)
while True:
username=input('请输入用户名: ').strip()
pwd=input('请输入用户名: ').strip()
with open('user.txt','r',encoding='utf-8')as f:
dic=f.read()
eval(dic)
if username in dic and pwd in dic:
user['user']=username
user['login_time']=time.time()
print('登录成功')
res=func(*args,**kwargs)
return res
else:
print('用户名或密码错误')
return wrapper
@auth
def home(n):
time.sleep(n)
print('welcome to home page')
@auth
def index():
time.sleep(1)
print('====>from index')
home(0.0001)
index()
方式二:
import time
# 1) 先将user.txt文件中的数据读取出来,把 str 转换成 dict 类型
with open('user.txt', 'r', encoding='utf-8') as f:
# 从文件中读取出来的都是字符串
user_data = f.read()
# print(user_data, type(user_data))
# 通过eval内置函数,将str ---> dict 类型
# eval,可以将字符串转行成python中对应的数据类型;
user_dict = eval(user_data)
# print(user_dict, type(user_dict))
# 用于记录是否有用户登录
user_login = {'user': None}
# 注意(涨知识):
# 在函数内部引用全局变量时,可变类型不需要global,不可变类型需要使用global
# 登录功能
def login():
while True:
username = input('请输入用户名: ').strip()
password = input('请输入密码: ').strip()
if username == user_dict.get('name') and password == user_dict.get('password'):
# 登录成功后,必须记录用户登录状态
# 将user_login全局变量,引用到函数内部来修改
# 以登录用户名 作为 字典的key, 以一个列表作为该用户的value值,value值的格式是 [用户名, 密码, 登录成功时的时间]
now_time = time.time()
user_login['user'] = [username, password, now_time]
print('login successful!')
break
else:
print('登录失败!')
# 2) 登录认证装饰器编写
def login_auth(func): # 被装饰的函数对象
def inner(*args, **kwargs): # 被装饰的函数对象的参数: 可能有,也可能没有
# 用户登录认证的逻辑
# [用户名, 密码, 登录成功时的时间]
user_info = user_login.get('user')
if user_info:
# 判断用户的登录时间是否失效, 假设判断超时时间为 5 秒
# 1) 获取当前时间
n_time = time.time()
if (n_time - user_info[2]) <= 5:
res = func(*args, **kwargs)
# 调用被装饰对象后添加的功能可以在此处写
return res
else:
login()
else:
# 调用登录功能,让用户去登录
login()
return inner
@login_auth
def pay():
print('pay...')
@login_auth
def transfer():
print('transfer...')
# 1) 先调用pay函数,此时未登录,装饰器就会先去执行登录功能
pay()
# 模拟延时6秒
time.sleep(6)
# 2) 执行到该行代码时,证明已经登录成功
transfer()
六:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
七:为题目五编写装饰器,实现缓存网页内容的功能:
具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
扩展功能:用户可以选择缓存介质/缓存引擎,针对不同的url,缓存到不同的文件中
八:还记得我们用函数对象的概念,制作一个函数字典的操作吗,来来来,我们有更高大上的做法,在文件开头声明一个空字典,然后在每个函数前加上装饰器,完成自动添加到字典的操作
方式一:
dic={}
def deco(name):
def wrapper(func):
dic[name]=func.__name__
return wrapper
@deco('story1')
def f1():
print('小鸟妈妈问小鸟:"今天扎什么发型"')
@deco('story2')
def f2():
print('小鸟说:"啾啾".')
print(dic)
方式二:
func_dic = {}
number = 1
def func_dict_add(func):
global number
func_dic[number] = func
# func_dic[func.__name__] = func
number += 1
def inner(*args, **kwargs):
res = func(*args, **kwargs)
return res
return inner
print('装饰前: ', func_dic)
@func_dict_add
def func1():pass
@func_dict_add
def func2():pass
@func_dict_add
def func3():pass
@func_dict_add
def func4():pass
@func_dict_add
def func5():pass
print('装饰后: ', func_dic)
九 编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017-07-21 11:12:11 f1 run写入到日志文件中,日志文件路径可以指定
注意:时间格式的获取
方式一:
import time
time.strftime('%Y-%m-%d %X')
def d_deco(func):
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
with open('access.log','a',encoding='utf-8')as f:
t=time.strftime('%Y-%m-%d %H:%M:%S')
msg=f'{t} {func.__name__} run\n'
f.write(msg)
return res
return wrapper
@d_deco
def f1():
print('小鸟妈妈问小鸟:"今天扎什么发型"')
@d_deco
def f2():
print('小鸟说:"啾啾".')
f1()
f2()
方式二:
import time
# 获取当前时间,并且是人能看得懂时间格式
# print(time.strftime('%Y-%m-%d %X'))
def wrapper(func):
def inner(*args, **kwargs):
timer = time.strftime('%Y-%m-%d %X')
with open('log.txt', 'a', encoding='utf-8') as f:
log_data = f'{timer} {func.__name__} run...\n'
f.write(log_data)
res = func(*args, **kwargs)
return res
return inner
@wrapper
def f1():
pass
f1()
f1()
f1()
f1()
f1()