装饰器说明
器指的工具(只要是工具,你就应该想到函数),装饰指的是为被装饰对象添加新功能,需要注意的是:项目一旦上线之后,就应该遵循开发封闭的原则。开发封闭指的是对修改函数内的源代码和调用方式是封闭的,对功能的扩展是开放的。看起来有点矛盾,但这就是我们要做的。在这样的要求下,我们必须要找到一种解决方案,能够在不修改一个功能内源代码以及调用方式的前提下,为其添加新功能。这就用到了装饰器,它能够在不修改被装饰对象源代码与调用方式的前提下,为被装饰器对象添加新功能。
无参装饰器
(1) 无参装饰器实现过程
无参装饰器指的是装饰器本身没有参数。
# 要求:为index函数添加一个统计时间的功能
import time # 这是一个与时间相关的模块
def index():
time.sleep(3) # 睡3秒
print('welcome to index page')
index()
# 版本一(只有index函数可以使用)
import time # 这是一个与时间相关的模块
def index():
time.sleep(3) # 睡3秒
print('welcome to index page')
start_time = time.time() # 从1970年开始计时的时间戳
index()
end_time = time.time()
print('run time is %s' % (end_time - start_time))
# 版本二(两个函数都可以使用,但是有大量重复代码)
def index():
time.sleep(3)
print('welcome to index page')
def home(name):
time.sleep(5)
print('welcome %s to home page' % name)
start_time = time.time()
index()
stop_time = time.time()
print('run time is %s' % (stop_time - start_time))
start_time = time.time()
home('Albert')
stop_time = time.time()
print('run time is %s' % (stop_time - start_time))
# 版本三(修改了源函数的调用方式)
import time
def index():
time.sleep(3)
print('welcome to index page')
def home(name):
time.sleep(5)
print('welcome %s to home page' % name)
def wrapper(func): # func=index
start_time = time.time()
func() # index()
stop_time = time.time()
print('run time is %s' % (stop_time - start_time))
wrapper(index)
# 版本四(使用闭包函数,不修改源函数调用方式)
import time
def index():
time.sleep(3)
print('welcome to index page')
def outer(func): # func=最原始的index
# func=最原始的index
def wrapper():
start_time = time.time()
func()
stop_time = time.time()
print(stop_time - start_time)
return wrapper
# a = outer(index) # outer函数结果可以赋值给任意变量
# b = outer(index)
# c = outer(index)
index = outer(index) # 赋值给index覆盖原来的index,index = wrapper
index() # wrapper()
# 版本五(解决原函数返回值无效)
import time
def index():
time.sleep(1)
print('welcome to index page')
return 1 # 假如源函数有一个返回值
def outer(func):
# func=最原始的home
def wrapper():
start_time = time.time()
res = func() # 调用最原始的index
stop_time = time.time()
print(stop_time - start_time)
return res
return wrapper
index = outer(index) # 新的index=wrapper
res = index() # 上一个版本返回值为None
print(res)
# 版本六(终极版,解决有参函数和无参函数通用的问题)
import time
def index():
time.sleep(1)
print('welcome to index page')
return 1
def home(name):
time.sleep(2)
print('welcome %s to home page' % name)
def timer(func): # 装饰器也是一个函数,我们给他一个好听的名字
def wrapper(*args, **kwargs): # wrapper函数有无参数由源函数决定
start_time = time.time()
res = func(*args, **kwargs)
stop_time = time.time()
print(stop_time - start_time)
return res
return wrapper
index = timer(index) # 新的index=wrapper
home = timer(home) # 新的home=wrapper
home(name='Albert') # wrapper(name='Albert')
home('Albert') # wrapper('Albert')
index() # wrapper()
# 无参装饰器模板
def outer(func):
def inner(*args, **kwargs):
"""
这里写装饰器逻辑
:param args: 任意位置参数
:param kwargs: 任意关键参数
:return: 一个函数对象
"""
res = func(*args, **kwargs)
return res
return inner(2) 装饰器语法糖
import time
# 装饰器也是一个函数,使用函数必先定义,所以装饰器放在最上方
def timer(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
@timer # 在被装饰对象正上方单独一行添加,相当于执行index=timer(index)
def index():
time.sleep(1)
print('welcome to index page')
return 1
# @timer # home=timer(home) 当不需要装饰器的时候只需注释这一行即可
def home(name):
time.sleep(2)
print('welcome %s to home page' % name)
index()
home('Albert')(3) 用户认证装饰器
import time
current_user = {
'username': None,
}
def auth(func):
def wrapper(*args, **kwargs):
if current_user['username']:
print('已经登陆过了')
res = func(*args, **kwargs)
return res
name = input('用户名>>: ').strip()
pwd = input('密码>>: ').strip()
if name == 'Albert' and pwd == '1':
print('登陆成功')
current_user['username'] = name
res = func(*args, **kwargs)
return res
else:
print('用户名或密码错误')
return wrapper
@auth
def index():
time.sleep(1)
print('welcome to index page')
return 1
@auth
def home(name):
time.sleep(2)
print('welcome %s to home page' % name)
index()
home('Albert')(4) 多个装饰器叠加
import time
current_user = {
'username': None,
}
def auth(func):
def wrapper(*args, **kwargs):
if current_user['username']:
print('已经登陆过了')
res = func(*args, **kwargs)
return res
name = input('用户名>>: ').strip()
pwd = input('密码>>: ').strip()
if name == 'Albert' and pwd == '1':
print('登陆成功')
current_user['username'] = name
res = func(*args, **kwargs)
return res
else:
print('用户名或密码错误')
return wrapper
def timer(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
"""
@auth
@timer # 这样写的话timer只统计index的执行时间
"""
@timer # timer 统计的是auth+index的执行时间
@auth
def index():
time.sleep(1)
print('welcome to index page')
return 1
index()有参装饰器就是装饰器本身需要一个参数,结合我们以前讲过的文件操作,其实文件就是存放数据的仓库,类似于数据库,数据库分很多种,常见的有MySQL,Oracle,PostgreSQL和DB2等等,在一些项目的需求中,不同的数据会分散存储在不同的数据库中,这时我们使用基于对象的数据模型(通俗讲就是使用编程语言来操作数据库)操作不同数据库就要执行不同的代码。
import time
current_user = {
'username': None,
}
def auth(engine):
def user_auth(func):
def wrapper(*args, **kwargs):
if engine == 'file':
print('基于文件的认证')
if current_user['username']:
print('已经登陆过了')
res = func(*args, **kwargs)
return res
name = input('用户名>>: ').strip()
pwd = input('密码>>: ').strip()
if name == 'Albert' and pwd == '1':
print('登陆成功')
current_user['username'] = name
res = func(*args, **kwargs)
return res
else:
print('用户名或密码错误')
elif engine == 'mysql':
print('基于MyQL的认证')
elif engine == 'ldap':
print('基于LDAP的认证')
elif engine == 'postgresql':
print('基于PostgreSQL的认证')
return wrapper
return user_auth
@auth('file') # auth装饰器本身是一个函数,在语法糖中也可以传参数
def index():
time.sleep(1)
print('welcome to index page')
return 1
index()from functools import wraps
def deco(func):
@wraps(func) # 加在最内层函数正上方
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@deco
def index():
'''哈哈哈哈'''
print(index.__doc__)
index()装饰器使用的是闭包函数的原理,返回的是和原来函数同名字的函数地址,再加上()就能调用这个函数,所以给我们的感觉是原来的函数没有变化,却添加了新的功能,其实已经不是原来的函数了,你可以把以上代码的第三行注释掉,运行代码,打印结果为None,就是因为你运行的函数已经不是原来的函数了,所以这其实是一个伪装饰器,要想让装饰器真的是装饰器,调用别人写好的包,返回结果还是原函数,以上写法就是。
| 留言与评论(共有 0 条评论) “” |