深究Python——装饰器
三个问题:
- 什么是装饰器?
- 手写装饰器?
- 装饰器都在哪里使用过或者说是见到过?
1. 什么是装饰器?
或者说为什么要用装饰器?
- 在 Python 中,装饰器是一种特殊的语法,为已有的对象添加额外的功能。装饰器本质上是一个 Python 函数或者类,它可以将其它函数或类作为参数或者返回值。 *装饰器的作用是在不改变被装饰对象源代码的情况下,添加额外的功能。
使用装饰器的好处:
- 代码重用:装饰器可以在多个函数或类之间重复使用,避免代码冗余。
- 动态增加功能:通过装饰器,可以在运行时动态地给对象增加新的功能或修改已有功能。例如,在 Flask 中,很多常见的功能都是通过装饰器实现的,比如身份验证、路由注册等。
- 简化代码结构:装饰器可以将一些通用的代码逻辑抽象出来,避免在每个函数中都写一遍相同的代码。这样可以让代码结构更清晰,易于维护。
- 提高代码可读性:装饰器可以把一些额外的逻辑和代码与源代码分离,让源代码更加简洁易懂。
- 解耦代码:通过装饰器,可以将不同的逻辑分离,减少代码之间的耦合。
- 总之,装饰器是 Python 中非常强大和灵活的一种功能,可以简化代码结构、提高代码可读性和可维护性,并在不改变源代码的情况下为代码动态增加新的功能。因此,装饰器非常流行,在 Python 中被广泛使用。
2. 手写装饰器?
- 下面是一个基础的函数:
def index(a1):
return a1 + 1000
v = index(2)
print(v)
print(index.__name__)
- 手写装饰器:
def wapper(func):
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
- 使用装饰器:
"""
@语法糖的作用:
1.看见@wrapper,执行wapper函数,并将被装饰的函数当做参数传递进去,即 wapper(index)
2.将第一步的返回值,重新赋值给 新index = wapper(老index)
"""
@wapper
def index(a1):
return a1 + 1000
v = index(999)
print(v)
print(index.__name__)
- 引出一个问题:
@wapper
def index(a1):
return a1 + 1000
@wapper
def order(a1):
return a1 + 1000
print(index.__name__)
print(order.__name__)
- 触发需求——当函数被装饰后,依然想通过
__name__获取原函数的名字? - 解决方法——在装饰器中使用内置的
functools.wraps():
import functools
def wapper(func):
@functools.wraps(func)
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
functools.wraps()这个装饰器的实现原理:
- 首先,每个函数都有自己的元信息(函数名/注释等),而functools.wraps()装饰器就会将原来函数(func)的元信息赋值给函数(inner)。
3. 装饰器都在哪里使用过或者说是见到过?
毋庸置疑,在这个专栏里写这篇文章,那就是Flask里使用过装饰器。其实前面每次注册路由,不都是用的装饰器吗?
- 直接看Flask中使用自定义装饰器:
from flask import Flask
from functools import wraps
app = Flask(__name__)
def wapper(func):
@wraps(func)
def inner(args, **kwargs):
print('before')
return func(args, **kwargs)
return inner
@app.route('/xxx')
@wapper
def index():
return 'Index'
@app.route('/aaa')
@wapper
def order():
return 'Order'
if __name__ == '__main__':
app.run()
注意点:
- 为了保证请求每次进来,装饰器都能执行,所以加的装饰器一定要在route下面;
- endpoint默认为函数名,不能有同名的(会报错),所以一定要使用functools的wraps装饰器。
装饰器——进阶:
下面是网上摘录的一段代码,看看你能否看懂为何会是这种输出顺序(里面附带注释): 欢迎在评论区留下你的思考痕迹~ 【感觉有必要多出几篇,深入讲一下装饰器,敬请期待~】
def wrapper1(func):
print('进入wrapper1了')
def inner1():
print('inner1')
func()
print('func1')
return inner1
def wrapper2(func):
print('进入wrapper2了')
def inner2():
print('inner2')
func()
print('func2')
return inner2
@wrapper2
@wrapper1
def f():
print('主函数')
f()