转载自 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. dubbo 配置解析

    1.dubbo 常用配置 <dubbo:service/> 服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心.eg.<dub ...

  2. windows中LNK文件打开方式恢复(每日一修(1))

    相信有些用户曾试过错误地把LNK文件的打开方式更改其他文件,导致系统所有的快捷方式都失效.在vista与Windows7系统还不普遍使用的时候,相信大家会有点惊慌失措,不要紧,下面只要大家进行如下操作 ...

  3. h5手机端下拉选择城市

    <!doctype html><html>    <head>            <meta http-equiv="Content-Type& ...

  4. 【poj2409】 Let it Bead

    http://poj.org/problem?id=2409 (题目链接) 题意 一个n个珠子的项链,每个珠子可以被染成t种颜色.项链可以翻转和旋转,问不同的染色方案数. Solution Pólya ...

  5. javaweb查看后台session和request所有的值

    遍历session @RequestMapping(value ="/test2") public String upload2( HttpSession session) { E ...

  6. UP board 漫谈(1)——从Atom到UP Board

    title: UP board 漫谈(1)--从Atom到UP Board date: 2016-12-26 12:33:03 tags: UP board categories: 开发板 perma ...

  7. 基于linux(centos)的svn环境搭建

    1. 安装svn yum intall subversion 2. 查看安装位置 rpm -ql subversion 3. 检验svn是否安装成功,查看帮助 svn --help , 看到下图表示成 ...

  8. Nginx 和 IIS 实现动静分离

    前段时间,搞Nginx+IIS的负载均衡,想了解的朋友,可以看这篇文章:<nginx 和 IIS 实现负载均衡>,然后也就顺便研究了Nginx + IIS 实现动静分离.所以,一起总结出来 ...

  9. std::unique_lock<std::mutex> or std::lock_guard<std::mutex> C++11 区别

    http://stackoverflow.com/questions/20516773/stdunique-lockstdmutex-or-stdlock-guardstdmutex The diff ...

  10. nginx + SSL优化配置

    nginx + SSL优化配置: #http段添加如下配置项: http { ssl_prefer_server_ciphers on; #设置协商加密算法时,优先使用我们服务端的加密套件,而不是客户 ...