转载自 http://python.jobbole.com/80956/

下面是Flask主页给我们的第一个例子,我们现在就由它入手,深入理解“@app.route()”是如何工作的。

 
 
 
 
 

Python

 
1
2
3
4
5
app = Flask(__name__)
 
@app.route("/")
def hello():
    return "Hello World!"

@app.route和其它装饰器

要想明白“@app.route()”的工作原理,我们首先需要看一看Python中的装饰器(就是以“@”开头的那玩意,下面接着函数定义)。

究竟什么是装饰器?没啥特别的。装饰器只是一种接受函数(就是那个你用“@”符号装饰的函数)的函数,并返回一个新的函数。

当你装饰一个函数,意味着你告诉Python调用的是那个由你的装饰器返回的新函数,而不仅仅是直接返回原函数体的执行结果。

还不是很明白?这里是一个简单的例子:

 
 
 
 
 
 

Python

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# This is our decorator
def simple_decorator(f):
    # This is the new function we're going to return
    # This function will be used in place of our original definition
    def wrapper():
        print "Entering Function"
        f()
        print "Exited Function"
 
    return wrapper
 
@simple_decorator
def hello():
    print "Hello World"
 
hello()

运行上述代码会输出以下结果:

Entering Function
Hello World
Exited Function

很好!

现在我们有点明白怎样创建我们自己的“@app.route()”装饰器了,但你可能会注意到有一个不同点,就是我们的simple_decorator不可以接受任何参数, 但“@app.route()”却可以。

那么我们怎样才能给我们的装饰器传参数?要实现这个我们只需创建一个“decorator_factory”函数,我们调用这个函数,返回适用于我们函数的装饰器。现在看看如果实现它。

 
 
 
 
 

Python

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def decorator_factory(enter_message, exit_message):
    # We're going to return this decorator
    def simple_decorator(f):
        def wrapper():
            print enter_message
            f()
            print exit_message
 
        return wrapper
 
    return simple_decorator
 
@decorator_factory("Start", "End")
def hello():
    print "Hello World"
 
hello()

给我们的输出是:

Start
Hello World
End
请注意在我们写@decorator_factory(“Start”, “End”)时,我们实际调用的是decorator_factory函数,实际返回的装饰器已经被用上了,代码很整洁,对吧?

把“app”放进“app.route”

现在我们掌握了装饰器怎样工作的全部前置知识 ,可以重新实现Flask API的这个部分了,那么把我们的目光转移到“app”在我们Flask应用中的重要地位上面来。

在开始解释Flask对象里面发生了什么之前,我们先创建我们自己的Python类NotFlask。

 
 
 
 
 

Python

 
1
2
3
4
class NotFlask():
    pass
 
app = NotFlask()

这不是个很有趣的类,不过有一样值得注意,就是这个类的方法也可以被用作装饰器,所以让我们把这个类写得更有趣一点,加一个称作 route的方法,它是一个简单的装饰器工厂。

 
 
 
 
 

Python

 
1
2
3
4
5
6
7
8
9
10
11
12
class NotFlask():
    def route(self, route_str):
        def decorator(f):
            return f
 
        return decorator
 
app = NotFlask()
 
@app.route("/")
def hello():
    return "Hello World!"

这个装饰器和我们之前创建的那些最大的不同,在于我们不想修改被我们装饰的函数的行为,我们只是想获得它的引用。

所以,最后一步是我们打算去利用一个特性,就是用装饰器函数的副产品去保存一个提供给我们的路径之间的链接,装饰器函数应该与它关联起来。

为了实现这个,我们给我们的NotFlask对象加一个“routes”字典,当我们的“decorator”函数被调用,路径将被插入新字典中函数对应的位置。

 
 
 
 
 

Python

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class NotFlask():
    def __init__(self):
        self.routes = {}
 
    def route(self, route_str):
        def decorator(f):
            self.routes[route_str] = f
            return f
 
        return decorator
 
app = NotFlask()
 
@app.route("/")
def hello():
    return "Hello World!"

现在我们就要完成了!可如果没法访问内部的视图函数,保存路径的字典又有什么用?让我们加入一个方法serve(path),当给定的路径存在时运行一个函数并给们我结果,当路径尚未注册时则抛出一个异常。

 
 
 
 
 
 

Python

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class NotFlask():
    def __init__(self):
        self.routes = {}
 
    def route(self, route_str):
        def decorator(f):
            self.routes[route_str] = f
            return f
 
        return decorator
 
    def serve(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 = NotFlask()
 
@app.route("/")
def hello():
    return "Hello World!"

在这个系列我们只关注重现那些热门库提供的友好API,所以钩挂“serve”方法实现一个HTTP服务器其实有一点超出本文的范围,当然结果是确定的,运行下述片段:

 
 
 
 
 

Python

 
1
2
3
4
5
6
7
app = NotFlask()
 
@app.route("/")
def hello():
    return "Hello World!"
 
print app.serve("/")

我们会看到:

Hello World!

我们已经完成了一个的Flask网页上第一个例子的非常简单的重现,让我们写一些快速测试检测我们简单重现的Flask的“@app.route()”是否正确。

 
 
 
 
 

Python

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class TestNotFlask(unittest.TestCase):
    def setUp(self):
        self.app = NotFlask()
 
    def test_valid_route(self):
        @self.app.route('/')
        def index():
            return 'Hello World'
 
        self.assertEqual(self.app.serve('/'), 'Hello World')
 
    def test_invalid_route(self):
        with self.assertRaises(ValueError):
            self.app.serve('/invalid')

吸口气。

完全正确!所以,仅仅是一个简单的包含一个字典的装饰器, 就重现了Flask的“app.route()”装饰器的基本的行为。

在本系列的下一篇,也是Flask的app.route()的最后一篇,将通过解析下面这个例子来解释动态URL模式是如何工作。

 
 
 
 
 

Python

 
1
2
3
4
5
; html-script: false ]app = Flask(__name__)
 
@app.route("/hello/<username>")
def hello_user(username):
    return "Hello {} !".format(username)

Python flask @app.route的更多相关文章

  1. Python Flask 开发学习笔记

    Flask学习 安装pipenv虚拟环境 pip Install pipenv 运行pipenv pipenv --version 进入虚拟容器 pipenv install 安装flask pipe ...

  2. Flask从入门到放弃1:路由app.route()

    Flask从入门到放弃1: Flask中的路由app.route(): 参考来源:http://python.jobbole.com/80956/ https://www.raspberrypi.or ...

  3. Python Flask 在Sina App Engine (SAE)上安家

    早就听说了Python的大名,随着的编程语言的理解加深,越发认为动态语言的威力--真大呀. 趁这段时间不忙,我也用Python写了一个应用,而且将其部署到Sina App Engine (SAE).S ...

  4. Flask - app.debug=True,python manage.py和export FLASK_DEBUG=True,flask run的不同。

    TL;DR,可以直接看下面的总结 问题1:为什么app.config['DEBUG'] = True,然后flask run并没有开启debugger和reloading,而直接运行脚本(python ...

  5. 【Azure 应用服务】Python flask 应用部署在Aure App Service 遇见的 3 个问题

    在App Service(Windows)中部署Flask应用时的注意事项: ● 添加Python扩展插件,Python 3.6.4 x64: ●● 配置 FastCGI 处理程序,添加Web.con ...

  6. 【Azure 应用服务】Python flask 应用部署在Aure App Service中作为一个子项目时,解决遇见的404 Not Found问题

    问题描述 在成功的部署Python flask应用到App Service (Windows)后,如果需要把当前项目(如:hiflask)作为一个子项目(子站点),把web.config文件从wwwr ...

  7. 【Azure 应用服务】Azure App Service For Linux 上实现 Python Flask Web Socket 项目 Http/Https

    问题描述 在上篇博文"[Azure 应用服务]App Service for Linux 中实现 WebSocket 功能 (Python SocketIO)"中,实现了通过 HT ...

  8. python flask route中装饰器的使用

    问题:route中的装饰器为什么感觉和平时使用的不太一样,装饰器带参数和不太参数有什么区别?被修饰的函数带参数和不带参数有什么区别? 测试1:装饰器不带参数,被修饰的函数也不带参数. def log( ...

  9. Flask系列03--Flask的路由 app.route中的参数, 动态参数路由

    Flask–路由 添加路由的两种方式 第一种 @app.route("/my_de") def detail() 第二种(了解即可) app.add_url_rule(" ...

随机推荐

  1. JavaScript模板引擎artTemplate.js——引入子模板

    之前的例子都是单一结构的对象,如果遇到复杂对象结构,我们可以通过引入子模板来实现html的渲染. 依旧以之前的数据作为例子: <div id="content">< ...

  2. 上传和设置Mime类型

    这两天一直在忙把主页上传的事,幸亏不久前花七块钱买了一年的数据库和虚拟主机,昨天上传了自己的个人主页,发现很多问题要改,因为代码一直没整理就那么放着了,大部分东西都要重新弄,然后把本地数据库的数据迁移 ...

  3. SpringBoot揭秘:快速构建微服务体系

    chapter 2: 饮水思源:回顾与探索Spring框架本质 IoC其实有两种方式,一种是DI(dependency Injection),一种是DL(dependency Lookup 依赖查找, ...

  4. css学习笔记(1)

    为什么要重新学css,理由有很多,css这个小婊砸,接触至今已有三年,但真的说熟练恐怕不见得.特此,为了我的目标,开始重新整理css的知识,我希望,每一篇笔记都能有个例子,从而来巩固我的知识. 在学习 ...

  5. 利用powerDesigner16.5连接oracle数据库并自动生成表结构图

  6. ASP.NET MVC 应用,站点发布到本地IIS

    材料准备 visual studio 2013 , iis 7 具体步骤 1.以管理员身份启动visual studio 2.新建项目 web app 或者站点 3.编译项目 4.右击项目选择publ ...

  7. 标题栏显示icon

    <link rel="shortcut icon" href="/favicon2.ico"/><link rel="bookmar ...

  8. kubernetes&tensorflow

    谷歌内部--Borg Google Brain跑在数十万台机器上 谷歌电商商品分类深度学习模型跑在1000+台机器上 谷歌外部--Kubernetes(https://github.com/kuber ...

  9. javaweb 基于java Servlet登入 简单入门案例

    项目流程 第一步:创建一个java webproject第二步:创建三个界面,1,login.jsp 2 success.jsp 3 fail.jsp第三步:更改新建界面编码格式,utf-8 默然编码 ...

  10. linux下配置yun源

    备份原yum源   /etc/yum.repos.d/centos一base.repo 下载yum源       wagt 源网址/源名称/etc/yum.repos.d/原yum名