理解@app.route()

 

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'
if __name__ == '__main__':
    app.run()

我觉得只要稍微看过 Flask 官方教程的小伙伴都会对这个代码很熟悉,熟悉归熟悉,那小伙伴们理解 **@app.route()**是如何发挥作用的吗?如果不清楚的话,嗯哼,just follow me~~

在理解这个之前,我们需要做一些准备。

@app.route 和 装饰器

为了理解 @app.route() 是如何发挥作用的,我们首先需要对 Python 中的装饰器有个大体的认识。具体的可以参考廖老师的教程--装饰器。老实说,装饰器其实就是在一个函数内部定义另外一个函数,然后返回一个新的函数,即动态的给一个对象添加额外的职责。如果还不是很明白的话,没关系,我们来看看具体的例子。

def simple_decorator(f):
    def wrapper():
        print "func enter"
        f()
        print "func exit"
    return wrapper

@simple_decorator
def hello():
    print "Hello World!"
    
hello()

运行一下上述代码,我们将会看到如下的输出:

 

看完这个例子,小伙伴们有没有稍微理解一点 @app.route() 了呢?可能有的小伙伴会说,@app.route() 是带参的,我们的装饰器并没有任何参数,这个很简单,接下来让我们试着,让我们的装饰器也可以传递参数。

def not_very_simply_decorator(enter_msg,exit_msg):
    def simple_decorator(f):
        def wrapper():
            print enter_msg
            f()
            print exit_msg
        return wrapper
    return simple_decorator

@not_very_simply_decorator("func enter","func exit")
def hello():
    print "Hello World"

hello()

是不是很奇怪,我为啥让两次的输出信息都一样,因为那样子,我只需要截一次图了~~哈哈,有没有觉得这个跟 app.route() 越来越有点像了,有的小伙伴肯定要说了,人家是 app.route(),而我的是 func(),那我只能说,咱们再接着往下看。

从 route() 到 app.route()的不归路

在此之前,如果有小伙伴跟我一样用 Pycharm 的话,使用它直接创建一个 Flask 项目,然后去点击 app.route()的话,会发现它跳转到了一个 Flask.py 的文件内,这个文件内容是一个 Flask 对象,而我们的 route() 函数就在其中,为了更好的理解 Flask 对象,我们可以尝试模仿它,创建一个类似的 Flask 对象。

class FlaskBother():
    def route(self,route_str):
        def decorator(f):
            return f
        return decorator

app = FlaskBother()

@app.route('/')
def hello():
    return 'Hello World'

看到这里,我就问一句,像不像?这个和我们之前创建的装饰器的主要区别在于,我们不想去修改我们装饰的这个函数的功能,我们只想去引用它,so 重点来了,聪明的你们知道,我们需要什么吗~~我们需要一个变量去存储路由和其关联的函数。那么 Flask 有没有这个变量呢,答案是肯定的,那我们如何在 Flask 中去查看所有的路由,以最初的最小的 Flask 为例。

进入Python交互模式

>>> from Hello import app

>>> app.url_map

Map([<Rule '/' (HEAD, OPTIONS, GET) -> hello>,

 <Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>])

好了说完在 Flask 中如何查看所有路由,为了在我们的 FlaskBother实现同样的功能,我们添加一个 "route" 字典到我们 FlaskBother 对象中。当我们的装饰器被调用的时候,我们将路由和关联的函数保存到我们的 "route" 字典中去。

class FlaskBother():
    def __init__(self):
        self.routes = {}
    def route(self,route_str):
        def decorator(f):
            self.routes[route_str] = f
            return f
        return decorator

app = FlaskBother()

@app.route("/")
def hello()
    return "Hello World"

其实到这里我们基本上已经完成了百分之90%了,我们现在唯一欠缺是一个可以访问内部 route 的途径,所以让我们再添加一个函数 server(path),通过这个函数我们可以通过路由去访问其关联的函数,如果没有的话,自然返回一个错误。

class FlaskBother():
    def __init__(self):
        self.routes = {}
    def route(self,route_str):
        def decorator(f):
            self.routes[route_str] = f
            return f
        return decorator
    
    def server(self,path):
        view_function = self.routes.get(path)
        if view_function:
            return view_function()
        else:
             raise ValueError('Route "{}" has not been registered'.format(path))

这就算完了吗?并没有,让我们尝试运行下面的程序:

app = FlaskBohter()
@app.route("/")
def hello():
    return "Hello World"

print app.server("/")

 

到这里不知道小伙伴们对 @app.route() 有没有一点理解~~如果还没有理解的话,不要急,我们慢慢来,如何将server(path) 挂载到 HTTP 服务器这里就不说了~~好了,小伙伴们下次见~~

欢迎小伙伴们扫码我的头像,关注我的微信号~我是桃子,和有趣的桃子用Python做有趣的事情。

编辑于 2018-09-15
原文地址:https://www.cnblogs.com/sddai/p/13426277.html