什么是装饰器:
给已有函数增加额外功能的函数,本质上是一个闭包。
装饰器功能特点:
1.不修改已有代码。
2.不修改已有函数的调用方式。
3.给已有函数增加额外功能。
装饰器的标准使用:
def count_time(func):
def inner():
start = time.time()
func()
end = time.time()
print(f'共用时{end-start} 秒')
return inner
@count_time
def show():
n = 0
for i in range(1000000):
n += 1
print('show - ',i)
show()
将show传给inner中的func。此时:show = count_time(show)。
结果是:
如果要给装饰器传递参数或者返回参数该怎么办呢?
python里还定义了一个通用装饰器。
通用装饰器:
# 定义一个通用装饰器(可以适合任何个数的参数)
def outerall(func):
def inner(*args,**kwargs):
print('装饰内容1:。。。。')
ret = func(*args,**kwargs)
print("装饰内容2:。。。")
return ret
return inner
@outerall
def showall(n,msg):
print(str(n) + msg)
print(type(n))
print(type(msg))
showall(1,'hahahaha')
结果为:
从中可以看出使用*args,**kwargs来作为接收元组,字典。通过这个通用装饰器即可实现多个参数的传输,返回。
多个装饰器的使用:
从下到上装饰,从上到下执行。
# 第一个闭包
def wrapper_div(func):
def inner(*args,**kwargs):
return '<div>' + func(*args,**kwargs) + '</div>'
return inner
# 第二个闭包
def wrapper_p(func):
def inner(*args,**kwargs):
return '<p>' + func(*args,**kwargs) + '</p>'
return inner
# 定义一个函数
@wrapper_div
@wrapper_p
def show():
return 'short life I use py'
print(show())
结果是:
就和糖衣一样,wrapper_div装饰在最上面,那么它显示的结果就在最外面,wrapper_p装饰器在div装饰器下面 ,它就在div装饰的里面。最里面就是内函数。
类装饰器:
使用类来作为装饰器。
class wrapper():
def __init__(self,func):
self.func = func
def __call__(self, *args, **kwargs):
print('装饰内容1.。。。')
ret = self.func()
print('装饰内容2.。。。')
return ret
@wrapper
def show(): # show = wrapper(show)
print('show run...')
show()
结果是:
可见:
# 如果是一个类实现的装饰器,那么该装饰器执行完成后,被装饰函数指向该类的实例对象 # 如果能让被装饰函数正常执行,那么在改实例对象的类中实现 __call__方法,就相当于闭包中的内函数 # 一旦被装饰的函数执行调用,那么就回去执行实例对象里的__call__函数
带有参数的装饰器:
就是使用装饰器装饰函数时,可以传入指定参数。
def set_arg(msg):
def set_func(func):
def inner():
print('装饰内容1....' + msg)
func()
return inner
return set_func
@set_arg('hello')
def show():
print('show run...')
show()
无论闭包函数定义成什么样 在使用该闭包进行装饰函数时 被装饰的函数 永远指向闭包函数的内函数。
有参数装饰器的应用:
实现一个自动维护的网页(大概)。
路由: 通过一个路径 可以去找到一个资源的地址。
# 定义一个网页的空字典
router_table = {}
# 定义一个用来自动维护路由的装饰器(带参)
def router(url):
def wrapper(func):
def inner():
print('inner -',func)
func()
# 在这里维护路由表
router_table[url] = inner
return inner
return wrapper
@router('index.html')
def index():
print('首页')
@router('center.html')
def center():
print('个人中心')
@router('maill.html')
def mail():
print('邮箱页面')
def error():
print('访问页面不存在')
def request(url):
# 先定义一个函数,指向错误页面
func = error
# 判断请求的url是否在字典里 如果在字典里 那么使用url 作为key,取出作为函数引用
if url in router_table:
func = router_table[url]
# 执行
func()
request('index.html')
request('center.html')
request('login.html')