(3) Flask pre-knowledge stack - decorator

Deep dive into Python - decorator

Three questions:

  1. What are decorators?
  2. Handwritten decorator?
  3. Where have the decorators been used or seen?

1. What is a decorator?

Or why use a decorator?

  • In Python, a decorator is a special syntax that adds additional functionality to an existing object. A decorator is essentially a Python function or class that can take other functions or classes as parameters or return values. The role of decorators is to add additional functionality without changing the source code of the object being decorated.

Benefits of using decorators:

  1. Code reuse: Decorators can be reused across multiple functions or classes to avoid code redundancy.

  2. Dynamically adding functions: Through decorators, new functions can be dynamically added to objects or existing functions can be modified at runtime. For example, in Flask, many common functions are implemented through decorators, such as authentication, route registration, etc.

  3. Simplify code structure: decorators can abstract some general code logic, avoiding writing the same code in each function. This makes the code structure clearer and easier to maintain.

  4. Improve code readability: Decorators can separate some extra logic and code from the source code, making the source code more concise and easy to understand.

  5. Decoupling code: Through decorators, different logic can be separated to reduce the coupling between codes.

  • In short, decorators are a very powerful and flexible feature in Python, which can simplify code structure, improve code readability and maintainability, and dynamically add new functions to code without changing the source code. For this reason, decorators are very popular and widely used in Python.

2. Handwritten decorator?

  • Here is a basic function:
def index(a1):
    return a1 + 1000

# 执行函数
v = index(2)
print(v)
# 获取函数名
print(index.__name__)

insert image description here

  • Handwritten decorator:
# 装饰器
def wapper(func):
    def inner(*args, **kwargs):
        return func(*args, **kwargs)
    return inner
  • Use a decorator:
"""
@语法糖的作用:
1.看见@wrapper,执行wapper函数,并将被装饰的函数当做参数传递进去,即 wapper(index)
2.将第一步的返回值,重新赋值给 新index = wapper(老index)
"""


# 使用
@wapper 
def index(a1):
    return a1 + 1000


v = index(999)
print(v)
print(index.__name__)   # 这里输出就不是index而是inner了,说明了上述说的第二步,即函数被重新赋值了
  • leads to a question:
@wapper
def index(a1):
    return a1 + 1000

@wapper
def order(a1):
    return a1 + 1000

# 下面输出都是inner
print(index.__name__)
print(order.__name__)
  • Trigger requirements - when the function is decorated, still want to __name__get the name of the original function?

  • Workaround - use builtin in decorator functools.wraps():

import functools


def wapper(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        return func(*args, **kwargs)
    return inner
    
# 将装饰器改成这样之后,上面那俩输出一个是index,一个是order

The implementation principle of the functools.wraps() decorator:

  • First, each function has its own meta-information (function name/comment, etc.), and the functools.wraps() decorator will assign the meta-information of the original function (func) to the function (inner).

3. Where have the decorators been used or seen?

Needless to say, writing this in this column, is that decorators are used in Flask. In fact, every time you register a route before, don’t you use a decorator?

  • Look directly at using custom decorators in 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()

important point:

  1. In order to ensure that the decorator can be executed every time the request comes in, the added decorator must be under the route;
  2. The endpoint defaults to the function name, and cannot have the same name (an error will be reported), so the wraps decorator of functools must be used.

Decorator - Advanced:

The following is a piece of code excerpted from the Internet, see if you can understand why this output order (with notes inside):
Welcome to leave traces of your thinking in the comment area~
[I feel that it is necessary to add a few more articles, let me explain in depth Check out the decorator, so stay tuned~]

def wrapper1(func):  # func ==  f函数名    #哪个糖靠近被装饰函数,哪个语法糖函数就先执行,但是内部的inner却后执行
    print('进入wrapper1了')

    def inner1():
        print('inner1')  # 2
        func()  # 这个函数func是被装饰的函数
        print('func1')  # 4

    return inner1  # @wrapper1最后一句f==inner1和@wrapper2后第一句f=wrapper2(f),变量替换,inner1 = wrapper2(f),这样就执行下面的装饰器函数了


def wrapper2(func):  # func == inner1   上面返回一个inner1 = wrapper2(f)
    print('进入wrapper2了')

    def inner2():
        print('inner2')  # 1
        func()  # 这里的func()其实是inner1(),到上面去了
        print('func2')  # 5

    return inner2


@wrapper2  # f = wrapper2(f)  里面的f==inner1  外面的f == inner2
@wrapper1  # f = wrapper1(f)   里面的f==函数名f  外面的f == inner1
def f():  # 3
    print('主函数')


f()  # inner2()

insert image description here

Guess you like

Origin blog.csdn.net/qq_44907926/article/details/131506552