1.3. 轻量级的Python Web框架

选择Python Web框架与选择任何其他软件工具没什么不同:它完全是为了适应目标和适应自己的开发习惯和偏好。

如果更喜欢minimal,只需创建一个REST API或在Web框架中包装现有的Python代码,这里描述的许多Python框架都非常适合你的需求。 在这方面,Flask和Bottle是很好的选择。 由于其紧凑性,Bottle特别适合包含在其他项目中。

Pyramid和CherryPy的项目结构相对较少,因此它们对于快速包装现有代码非常有用。 在这方面,Falcon和Tornado更加轻量。 它们的开销很小,但也缺乏更强大的Web应用程序所需的更重的工具。 Web.py是涉及用户交互(例如表单提交)的应用程序的快速起点。 Wheezy.web和它的库允许按照自己想要的功能去做。

对于具有更高端需求的开发人员而言,Django是最好的起点之一,不仅因为其拥有丰富的开箱即用组件,而且庞大的用户社区多年来取得了巨大成功。 如果你不需要这样的完整性,Weppy是一个很好的折衷方案,因为它比更小的框架具有更多扩展的功能集。

最后,虽然CubicWeb和Zope2仅提供整个开发环境而不是框架,使用它们是以学习它们的特性为代价的。

1.3.1. Bottle

Bottle比其他“微框架”更加紧凑和简洁。 Bottle非常适合包含在其他项目中或快速交付REST API等小型项目。

Bottle的整个代码库适合单个文件,并且绝对没有外部依赖性。 即便如此,Bottle还配备了足够的功能来构建常见的Web应用程序,而无需依赖外部帮助。

Bottle中的路由系统将URL映射到函数,其语法与Flask几乎完全相同。 也不仅限于硬连线路径;可以动态创建它们。 可以通过Bottle框架中的对象访问和操作请求和响应数据,cookie,查询变量,来自POST操作的表单数据,HTTP标头和文件上载。

每项功能都经过精心细致的实施。 例如,使用文件上载,如果文件的命名约定与目标文件系统冲突(例如Windows上的名称中的斜杠),则不必重命名该文件;瓶子可以帮到你。

Bottle包含自己的简单HTML模板引擎。 同样,虽然很小,但它已经装配好了必需品。 默认情况下,模板中包含的变量使用安全HTML呈现;你必须指出哪些变量可以安全地从字面上重现。 如果更换掉模板引擎并使用另一个模板引擎,例如Jinja2,那么Bottle可以帮助轻松完成。 我其实喜欢与Bottle捆绑的简单模板系统;它的语法不起眼,它允许混合代码和模板文本而不会有不适当的困难。

Bottle甚至支持多个服务器后端。 它配备了自己的内置miniserver以进行快速测试,但可以支持各种兼容WSGI的HTTP服务器,并在需要时可以回退到普通的旧CGI。

Bottle不需要像其他框架那样多的文档,但文档绝不是吝啬。 所有关键的东西都适合单个(尽管很长)的网页。 除此之外,还可以找到每个API的完整文档,如何在各种基础架构上进行部署的示例,内置模板语言的解释以及一系列常见配方。

与Flask一样,可以手动或通过编写补充瓶的插件扩展Bottle的功能。 Bottle插件列表远不及Flask的大小,但有一些有用的部分,例如与各种数据库层的集成和基本的用户身份验证。 对于异步支持,Bottle可以使用异步运行的现有服务器适配器之一,例如aiohttp/uvloop。

Bottle极简主义的一个后果是有些功能根本就不存在。 不支持表单验证,包括CSRF保护等功能。 如果要构建支持高度用户交互的Web应用程序,则需要自己添加它们。

1.3.2. CherryPy

CherryPy已经存在了超过10年,但并没有失去它的极简主义和优雅。

这个框架的前提是,除了只包含为web页面提供服务所需的少量内容外,它应该尽可能地让人感觉它不像“web框架”,而是像任何其他类型的Python应用程序一样。 根据文件显示,Hulu和Netflix等网站在制作中使用了CherryPy,这可能是因为该框架提供了一个高度低调的基础。

CherryPy可以将Web应用程序与核心逻辑区分开来。 要将应用程序的功能映射到CherryPy提供的URL或路由,需要创建一个类,其中对象的名称空间直接映射到您要提供的URL;例如,网站的根由名为“index”的函数提供。 传递给这些函数的参数用于处理由GET或POST方法提供的变量。

CherryPy包含的位用作低级构建块。 包括会话标识符和cookie处理,但不包括HTML模板。 像Bottle一样,CherryPy提供了一种将路由映射到磁盘上的目录以供静态文件服务的方法。

CherryPy通常会遵循现有的第三方库来支持某个功能,而不是尝试本机提供它。 例如,CherryPy不直接支持WebSocket应用程序,而是通过ws4py库支持。

CherryPy的文档包含一个方便的教程,介绍了该程序的各个方面。 与其他框架教程不同,它不会引导完成一个完整的端到端应用程序,但它仍然有用。 这些文档提供了有关各种场景中部署的方便说明,包括虚拟主机,通过Apache和Nginx的反向代理以及许多其他方案。

CherryPy在引擎下使用池化线程,更好地支持多线程服务器适配器。 如果想尝试其他方法,CherryPy的非官方第三方分支交换asyncio协程而不是线程。

1.3.3. Falcon

如果正在构建基于REST的API而不是其他任何东西,那么Falcon提供的绝对必要。 它的设计精简而快速,几乎没有标准库之外的依赖关系。

Falcon获得“轻薄”标签的原因很大一部分与框架中的代码行数无关。 这是因为Falcon在应用程序上几乎没有任何结构。 Falcon应用程序所要做的就是指出哪些函数映射到哪些API端点。 从给定端点返回JSON只需设置路由并通过Python标准库中的json.dumps函数从中返回数据。

Falcon还采用了理智的开箱即用默认设置,因此安装时几乎不需要修改。 例如,对于未明确声明的任何路由,默认情况下会引发404。 如果要将错误返回给客户端,可以引发与框架捆绑在一起的许多库存异常中的一个(例如HTTPBadRequest)或使用泛型falcon.HTTPError异常。 如果需要为给定路线进行预处理或后处理,Falcon也会为这些路径提供挂钩。

Falcon对API的关注意味着用传统的HTML用户界面构建Web应用程序几乎没有。 例如,表单处理功能和CSRF保护工具几乎不存在。 也就是说,Falcon提供了优雅的选项来扩展其功能,因此可以构建更复杂的项目。 除了上面提到的挂钩机制之外,还可以找到一个用于创建中间件的界面,该界面可用于包装所有Falcon的API。

Falcon的文档与其他框架相比比较细长,但仅仅因为它的覆盖范围较小。 用户指南包括所有主要功能的正式逐步演练,以及一个快速入门部分,可让您查看带或不带注释的示例代码。

1.3.4. Flask

关于Python中的Web框架的大多数讨论都是从Flask开始提到的,并且有充分的理由。 Flask是一个成熟的,易于理解的框架,广泛使用且非常稳定。 使用Flask进行轻量级Web项目或基本REST API几乎不可能出错,但如果试图构建更大的东西,将面临繁重的工作。

Flask的核心吸引力在于其进入门槛低。 一个基本的“hello world”Flask应用程序可以在少于10行的Python中实现。 广泛使用的HTML模板系统Jinja2附带了使渲染文本变得容易的框架,但是Jinja2可以换成任何数量的其他模板引擎(例如Mustache),或者可以自己动手。

Flask核心不包括许多功能,例如,它没有开箱即用的数据层或ORM,也没有类似表单验证的规定。 但是,它可以通过扩展进行扩展,其中有几十个,包括许多常见用例,如缓存,表单处理和验证,数据库连接等。 这种默认设计允许开始设计具有绝对最小功能的Flask应用程序,然后仅在需要时将所需的部分分层。

Flask的文档非常出色地帮助启动和运行,同时还解释了为简单的Flask应用程序所做的默认选择的重要性,并且API文档充满了如何使用所有内容的良好示例。 同样优秀的是“片段”的集合,这些片段是如何使用Flask完成特定任务的快速和肮脏的示例,例如如果存在如何返回对象,如果不存在则返回404错误。

1.3.5. Pyramid

小而轻,Pyramid比Django更接近Flask甚至Falcon。 因此,它非常适合于将现有Python代码公开为REST API,或者为开发人员完成大部分繁重任务的Web项目提供核心的任务。

描述Pyramid极简主义的一个好方法是“无策略”,这是在文档部分中使用的一个术语,用于讨论Pyramid如何与其他Web框架形成对比。 你使用什么样的数据库或什么样的模板语言不是金字塔的关注点。

构建基本的Pyramid应用程序只需要很少的工作。 与Bottle和Flask一样,Pyramid应用程序可以包含单个Python文件,除了框架本身的文件。 一个简单的单路径API不需要十几行代码。 其中大部分是来自… import语句和设置WSGI服务器的样板。

默认情况下,Pyramid包含Web应用程序中常见的几个项目,但它们是作为要拼接在一起的组件提供的,而不是完整的解决方案。 例如,包括对用户会话的支持,它甚至还带有CSRF保护。 但是对Django提供的用户帐户(例如登录或帐户管理)的支持不是交易的一部分。 您必须自己滚动或通过插件添加它。 表单处理和数据库连接也是如此。

Pyramid避免过于极小的一种方法是通过提供从Pyramid项目制作模板的方法来重用或重新使用先前的工作。 这些模板,即Scaffolds,生成一个带有简单路由和一些入门HTML / CSS模板的Pyramid应用程序。 默认情况下,Pyramid包含的支架包括一个示例启动项目和一个通过常用的Python库SQLAlchemy连接到数据库的项目。

Pyramid在测试和调试工具方面同样细长。 在Pyramid应用程序中捆绑debugtoolbar扩展,将在应用程序生成的每个网页上获得一个可点击图标,该图标生成有关应用程序执行的详细信息,包括发生错误时的详细回溯。 还存在记录和单元测试,即使从这个轻量级的框架中排除两个看起来也很愚蠢的项目。

Pyramid的文档很棒。 除了快速浏览基础知识和教程式演练之外,还可以找到一组社区贡献的教程,用于构建各种项目和常用食谱的烹饪手册。 后者包括针对大量目标环境的部署技术,从Google App Engine到Nginx。

Pyramid支持Python 2和Python 3,但不使用Python 3的异步语法。 有关如何在Pyramid中利用异步的线索,请参阅aiopyramid项目,其中包括用于异步驱动的“hello world”应用程序的脚手架。

1.3.6. Tornado

Tornado是针对特定用例的另一个小框架。 Tornado专为构建异步网络应用程序而设计,非常适合创建同时打开大量网络连接并使其保持活动状态的服务,即涉及WebSockets或长轮询的任何内容。

像Bottle或Falcon一样,Tornado省略了与其核心目的无关的特征。 例如,Tornado有一个内置的模板系统,用于生成输出(以HTML或其他方式)和国际化,表单处理,cookie设置,用户身份验证和CSRF保护的机制。 但是它省略了类似于表单验证和ORM的功能,它们更适合面向用户的Web应用程序。

Tornado擅长为需要严密控制异步网络细节的应用程序提供基础架构。 例如,Tornado不仅提供内置的异步HTTP服务器,还提供异步HTTP客户端。 因此,Tornado非常适合构建应用程序,例如Web scraper或bot,它们并行查询其他站点并对返回的数据进行操作。

如果正在尝试创建一个使用HTTP以外的协议的应用程序,Tornado会提供帮助。 它提供对DNS解析器以及第三方认证服务等实用程序的低级TCP连接和套接字的访问,并支持通过WSGI标准与其他框架进行互操作。 文档很小但不稀疏,包含了如何完成所有这些的大量示例。

Tornado既利用并补充了Python的异步行为本机功能。 如果使用的是Python 3.5,Tornado支持内置的异步和等待关键字,它们可以为应用程序提供速度提升。 对于早期版本的Python,可以使用yield语句。 在任何一种情况下,都可以使用期货或回调来处理对事件的响应。

Tornado 5.0改进了与Python的本机异步功能的集成。 因此不再支持Python 3.3,并且Python 3.5用户必须使用Python 3.5.2或更高版本。 Tornado 6.0将需要Python 3.5及更高版本,并将完全放弃Python 2支持。

Tornado还提供了一个同步原语库,信号量,锁等,以协调异步协程之间的事件。 请注意,与Python解释器本身一样,Tornado通常运行单线程,因此这些原语与其线程名称不同。 但是,如果想在并行进程中运行Tornado以利用多个套接字和内核,那么可以使用这些工具。

Tornado的文档涵盖了框架中的每个主要概念以及模型中的所有主要API。 虽然它包含一个示例应用程序(网络抓取工具),但它主要用于演示Tornado的排队模块。

1.3.7. Web.py

Web.py最初是由已故的Aaron Swartz创建的,并被用作Reddit的原始基础。 尽管Reddit可能已经从Web.py转移,但Web.py继续由其他人维护,主要是Anand Chitipothu。 在范围和设计上,Web.py类似于Bottle和Flask;你可以把它当作一个基本的骨架,然后在它上面构建,而不会感觉太受限制。

要调用基本的Web.py实例,需要做的就是传递一个URL和函数映射列表。 URL可以包含带有捕获参数的正则表达式,允许使用/users/RayB或/article/451等格式从URL中提取数据。 Bottle具有类似的机制,但也提供了确保参数符合某些标准的方法(例如,它们只能是整数)。

Web.py在很大程度上保持干净和朴素,因为它不会尝试承担其他机制更好处理的任务。 例如,没有本机功能允许从Web.py堆栈提供静态内容;说明明智地建议改为通过Web服务器。 相比之下,Bottle具有提供静态内容的本机功能,尽管它是可选的。 Web.py还包括cookie和会话管理,甚至还有一个简单的输出缓存。

Web.py有一个HTML模板系统;它是非常基本的,但允许if/then/else逻辑。 更复杂,更有用的是Web.py的动态生成HTML表单的系统,具有CSS样式的类属性和基本的表单验证机制。 如果希望使用以编程方式生成的表单(例如基本数据库资源管理器)生成应用程序,这将非常方便。

Web.py的文档与框架本身一样小,但它并没有提供相关的示例。 “cookbook”部分(多种语言,不低于)演示了许多常见用例(提供静态内容,逐步传输大型文件等)。 甚至还有一个使用该框架构建的真实Web应用程序库,其中许多都带有源代码。

请注意,Web.py并未像其他框架一样保持与Python 3兼容性的最新状态。 这不仅意味着缺乏对异步语法的支持,还意味着缺少对已弃用的函数的错误。 此外,目前尚不清楚维护者是否有计划在Python 2到达其支持生命周期结束后保持Web.py的最新状态。

1.3.8. Wheezy.web

Wheezy.web是Web框架的Flask/Bottle/Pyramid模型:小巧轻便,专注于提供高速和高并发性。 这个功能集的核心是小的,但它的创建者已经为它配备了各种必备功能。

谈论Wheezy.web作为单一产品有点误导。 Wheezy.web将同一作者创建的其他几个库粘合在一起,每个库根据希望应用程序的操作提供不同的服务。 例如,Wheezy.http库被Wheezy.web大量用于许多基本行为,但除非应用程序必须执行用户身份验证,否则不需要Wheezy.security库。

这种库集合方法意味着使用Wheezy开发的最简单方法是从PyPI安装它或使用easy_install来收集所有相关的包。 我在Python 3.51中使用easy_install时遇到了问题,但它在Python 2.7中运行良好。

Wheezy.web的核心主要是将路由映射到函数和处理重定向,但它配备了一些其他有用的功能。 例如,使用@secure装饰器标记的任何路由将仅接受HTTPS请求,并且如果进行HTTP连接尝试将重定向到HTTPS。 另一个核心添加是中间件,以便可以自定义路径路由和HTTP错误。

Wheezy的其他库涵盖了一组相当丰富的用例。 Wheezy.validation可以帮助确保提交的数据满足特定条件,例如,用户名或密码满足长度或复杂性要求。 Wheezy.caching允许缓存未更改的响应以加速处理,Wheezy.captcha与Python的PIL/Pillow图像库集成以生成验证码。 对于国际化,它与标准GNU gettext实用程序集成。

核心Wheezy.web框架不包含模板引擎。 如果需要做的不仅仅是返回纯文本或JSON,可以添加Wheezy.template引擎或连接许多第三方引擎,如Jinja2和Mako。 Wheezy.web也省略了ORM; Wheezy文档中的示例通过手动SQL字符串使用SQLite。

使用Wheezy构建应用程序需要比使用Flask或Bottle更多的样板,但不要过分;其中大部分涉及设置路线和中间件,这些东西可以在不费力的情况下抽象出来。 Wheezy的文档中详细解释了这些细节,其中包括“创建留言簿”教程,但其他方面则是关于奖金的。

Wheezy的开发似乎已经停滞不前,因为该项目的最后一次提交都记录在2015年。 这对于保持与新Python功能的兼容性并不是好兆头。

1.3.9. Sanic Document

这次我们来介绍一个 web 框架:Sanic,它既是一个 web 框架,同时也是一个 web 服务器。

关于框架,首先浮现在脑海中的就是 Flask、Django 之类的,但它们都是同步框架,而现在是一个高并发的时代,并发量是在构建服务时必须考量的一个指标。

所以我们自然就想到了 Python 中的异步框架,而提到异步框架,那么就必须要提 Sanic、FastAPI,这两个异步框架都很优秀,但是 Sanic 的表现要更加出色,使用 Sanic 构建的应用程序足以比肩 Nodejs。 如果你再对 Sanic 在路由处理方面使用 C 语言做一些重构,那么并发性能可以和 Go 相媲美。

那么 Sanic 为什么这么快呢?肯定是有原因的,首先它是一个异步框架,使用了 Python 中的协程。

而提到协程必然少不了事件循环,而事件循环的构建依赖于 asyncio 这个库,但 asyncio 构建的事件循环效率是不高的,所以有一个第三方库 uvloop。

uvloop 使用 Cython 编写,基于 libuv,它可以让 asyncio 变得更快。

当然即便我们不开发 Sanic 服务,也可以使用 uvloop 来替换 asyncio 内部的事件循环。

import asyncio
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

只需要以上几步,便可以让 asyncio.get_event_loop() 构建一个速度更快的事件循环。

但是有一点需要注意,uvloop 不支持 Windows 系统,但是这并不妨碍我们在 Windows 上开发 Sanic 服务, 因为内部虽然会导入 uvloop,但是做了一个异常捕获,所以导入失败话,会使用原生的 asyncio 事件循环。

因此即使你用 Windows,安装 Sanic 也没有问题,因为 uvloop 不会自动安装。 但如果是在 Linux 上,uvloop 会自动帮我们安装。

此外在解析 json 的时候,使用的不是标准库中的 json,而是 ujson,ujson 解析数据也要比标准库的 json 快很多。

当然 ujson 也不会在安装 Sanic 的时候自动安装,也需要我们手动安装,但它是支持 Windows 平台的。

而在语法特性层面,Sanic 提供了和 Flask 类似的路由注册模式, 即可以通过装饰器的模式,而且 Sanic 内部也有 “蓝图” 这个概念,用于对业务进行逻辑分离。

如果你会 Flask 的话,那么很容易上手 Sanic,因为开发模式非常类似,当然不熟悉 Flask 也没有关系,因为 Sanic 本身和 Flask 一样简单。

下面我们来安装 Sanic,直接 pip install sanic 即可,安装之后我们就来学习如何使用 Sanic 框架编写我们的 web 服务。