Python装饰器

文章目录

  • 一、装饰器的实现
  • 二、装饰器到底干了什么
  • 三、有多个装饰器时,装饰器对函数的包装顺序
  • 四、装饰器的应用

一、装饰器的实现

这个问题可以参考廖老师的文章,很详细了,此处只简单举例,不做详细介绍。
文章链接:
https://www.liaoxuefeng.com/wiki/1016959663602400/1017451662295584

def log(f):
    def wrapper(*args, **kw):
        print("log")
        return f(*args, **kw)
    return wrapper

@log
def test():
    print("Just a test.")

二、装饰器到底干了什么

以上面的代码为例,我们使用装饰器时用了@log。在运行时,此处相当于执行了test = log(test),如果将@log改为@log("2020"), 那么此处就相当于执行了test = log("2020")(test)。可以简单理解为程序将@后面的语句拿出来,添加(func_name)后再赋给原函数变量。
Python装饰器_第1张图片

要注意的是,后面的部分是真的执行了,如上面的代码就是执行了log(test)

再如flask中,通过app.route注册视图函数:

@app.route("/index")
def index():
    ...

通过这段代码,程序会自动注册index,我们访问/index时程序会自动执行index函数中的内容,并不需要额外的操作。那么注册的代码是在什么时候运行的呢?
还是之前说过的,程序运行到此处,相当于开始执行index = app.route("/index")(index),在执行过程中完成了注册。
看下app.route的源码:

    # app.route
    def route(self, rule, **options):
        def decorator(f):
            endpoint = options.pop("endpoint", None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator

可以发现,执行app.route("/index")(index)时,执行了decorator(index), 在decorator注册了视图函数f,并将f直接返回。所以此处执行index = app.route("index")(index)后,index函数并未改变。

三、有多个装饰器时,装饰器对函数的包装顺序

django中有定义好的一个装饰器,叫login_required。通过它,可以设置对应视图函数在登陆后才能访问。那么在flask中我们如何手动实现它?
flask中的视图函数都有了app.route装饰器,再添加一个装饰器要放到@app.route上面还是下面?

我们测试下:

def outter(f):
    def wrapper(*args, **kw):
        print("outter")
        return f(*args, **kw)
    return wrapper


def inner(f):
    def wrapper(*args, **kw):
        print("inner")
        return f(*args, **kw)

    return wrapper


@outter
@inner
def test1():
    print("test1")


def test2():
    print("test2")


print("test1:", test1)
print("------")
print("outter(inner)(test2): ", outter(inner)(test2))
print("------")
print("outter(inner(test2)): ", outter(inner(test2)))

运行结果如下:

test1: .wrapper at 0x01B7E340>
------
outter
outter(inner)(test2):  .wrapper at 0x01B7E4F0>
------
outter(inner(test2)):  .wrapper at 0x01B7E2B0>

这里用test2是因为test1已经被改变了。
从结果可以看出,多个装饰器间的执行顺序是从内到外的,先执行inner(test2),再将inner(test2)的结果作为outter的参数。

四、装饰器的应用

在这里我们简单的实现下flask的login_required装饰器。
我们要实现登录认证,可以从session中获取用户的登录信息,如果获取到就继续,否则就跳转到登录页:

import functools


def login_required(f):
    @functools.wraps(f)
    def wrapper(*args, **kw):
        if session.get("username", None) is not None:
            return f(*args, **kw)
        return login()
    return wrapper

使用:

@app.route("/index")
@login_required
def index():
    ...

你可能感兴趣的:(Python,python)