Python/ target=_blank class=infotextkey>Python的便利性和多功能性意味着它几乎被用于构建各行各业的软件。一个主要的利基是web服务,Python的开发速度和灵活性使其可以很容易地快速建立和运行网站。正如您可能猜到的那样,Python在web框架中为您提供了大量的选择和自由度,无论大小。毕竟,不是每个web项目都需要是企业级的。大多数应该能足够完成工作就可以了,而不是追逐更大。本文将8个最知名的Python框架,它们强调简单性、轻量级交付,接下来就具体点地了解下这些框架。
Bottle(http://bottlepy.org/)可以被认为是一种迷型Flask,因为它甚至比其他的“微框架”更紧凑和简洁。由于Bottle占用的空间很小(最小化封装),所以它非常适合包含在其他项目中,或者用于快速交付像REST APIs这样的小项目。(后面会讨论Flask。)
Bottle的整个代码库都可以放在一个文件中,并且完全没有外部依赖关系。即便如此,Bottle还是配备了足够的功能来构建常见的web应用程序,而不需要依赖外界的帮助。
Bottle中的路由系统将url映射到函数,其语法与Flask几乎完全相同。应用中你也不会被局限于一组硬连接的路径,而是可以动态地创建它们。请求和响应数据、cookie、查询变量、POST操作的表单数据、HTTP报头和文件上传都可以通过Bottle的对象访问和操作。
每一项能力的实现都很注意细节。例如,对于文件上传,如果文件的命名约定与目标文件系统冲突(例如在windows中文件名中的斜杠),则不必重命名文件。Bottle可以帮你做到这一点。
Bottle包含有它自己的简单html模板引擎。同样,尽管模板引擎很小,但它具有所有的基本功能。模板中包含的变量默认使用安全HTML渲染;同时你必须指出,哪些变量是安全的,以便按照字面意思重新生成。如果您愿将Bottle的模板引擎换为另一个模板引擎,比如Jinja2,那么Bottle可以让您轻松地这样做。我更喜欢与Bottle捆绑的简单模板系统;它速度快,语法朴实无华,并且允许您在不太困难的情况下混合代码和模板文本。
Bottle甚至支持多个服务器后端。它自带了用于快速测试的内置迷你服务器(内置了开发服务器),而且还支持通用的WSGI、各种与WSGI兼容的HTTP服务器,如果需要,也可支持普通的旧式CGI。比如,在Bottle中的“Hello World”程序:
from bottle import route, run, template
@route('/hello/<name>')
def index(name):
return template('<b>Hello {{name}}</b>!', name=name)
run(host='localhost', port=8080)
运行此脚本或将其粘贴到Python控制台,然后将浏览器指向
http://localhost:8080/hello/world。就这样实现了编程中“经典”。
与其他框架相比,Bottle不需要那么多的文档,但是它的文档也绝不少。所有的关键内容都适用于单页面(虽然很长的)。除此之外,您还可以找到每个API的完整文档、在各种基础设施上部署的示例、对内置模板语言的解释和大量常用方法。
与Flask一样,您可以手动或通过插件扩展Bottle的功能。Bottle插件远没有Flask插件那么多,但是拥有着一些有用的部分,如与各种数据库层的集成和基本的用户身份验证。对于异步支持,Bottle可用现有的异步运行的服务器适配器,比如aiohttp/uvloop,但是sync/await不是原生支持。
Bottle的极简设计的一个后果就是有些东西根本就不存在。表单验证,包括CSRF(cross-site request forgery,跨站点请求伪造)保护特性没有包括在内。如果您想构建一个支持高度用户交互的web应用程序,您需要自己添加这种支持。
Bottle的另一个问题是发展已经迟滞很久了,最新版本是0.12,最开始是在2013年发布的,后又小版本更新(最新稳定版是2019年12月发布的0.12.18,开发中的0.13版还没正式发布)。也就是说,Bottle将继续被维护,并且它的开发版本仍然可以用于生产。开发人员打算交付新的版本,以摆脱对Python的遗留版本的支持。
关于Bottle下载与安装
使用pip install bottle安装最新的稳定版本,或者将bottle.py(不稳定)下载到您的项目目录中。除了Python标准库之外,Bottle没有硬依赖项。Bottle支持Python 2.7和Python 3。
注意,自0.13版本开始不推荐在Python 2.5和2.6下使用Bottle,此版本去掉了对它们的支持。
概要总结一下:Bottle是一个快速和简单的微型框架,用于小型web应用程序。它提供了url参数支持、模板、内置HTTP服务器和许多用于第三方WSGI/HTTP- Server和模板引擎的适配器服务于请求分派(路由)——所有这些都在一个文件中,除了Python标准库之外没有其他依赖关系。
CherryPy(http://www.cherrypy.org/)已经以这样或那样的形式存在了将近20年,但并没有失去它从一开始就与众不同的极简主义和优雅。
CherryPy背后的目标,除了只包含服务web页面所需要的少量内容之外,是尽可能让人感觉不像“web框架”,而是像任何其他类型的Python应用程序。像Hulu.NETflix这样的网站已经在生产中使用了CherryPy,因为这个框架提供了一个非常包容的构建基础。CherryPy在底层使用线程池,更好地支持多线程服务器适配器。
CherryPy可以让您的web应用程序远离核心逻辑。要将应用程序的函数映射到CherryPy提供的url或路由,需要创建一个类,其中对象的名称空间直接映射到需要提供服务的url。例如,网站的根目录由一个名为“index”的函数提供。传递给这些函数的参数用于相应的处理GET或POST方法提供的变量。
CherryPy包含的比特意味着作为低级构建块工作。包含了Session标识符和cookie处理,但没有包含HTML模板。与Bottle一样,CherryPy提供了一种将路由映射到磁盘目录的方法,用于静态文件服务。
CherryPy通常会遵从现有的第三方库来支持某个特性,而不是本地化(原生)提供它。例如,WebSocket应用程序不是由CherryPy直接支持的,而是通过ws4py库支持的。
CherryPy的文档包含一个方便的教程,介绍了该程序的各个方面。与其他一些框架教程不同,它不会带您了解完整的端到端应用程序,但仍然很有用。文档中有关于虚拟主机部署、通过Apache和Nginx进行反向代理以及许多其他场景的便签笔记式说明。
应用示例代码如下:
import cherrypy
class HelloWorld(object):
@cherrypy.expose
def index(self):
return "Hello World!"
cherrypy.quickstart(HelloWorld())
如果您正在构建基于REST的APIs,那么Falcon(
http://falconframework.org/)就是专门为您设计的。精悍、快速,除了标准库之外几乎没有依赖,Falcon提供了REST api所需的一切,仅此而已。2019年发布的Falcon2.0废除了对Python 2.x支持,并且至少需要Python 3.5。
Falcon获得“轻薄”(light & slender)标签的很大一部分原因与框架中的代码行数无关。这是因为Falcon几乎没有将自己的结构强加给应用程序。Falcon应用程序所要做的就是指出哪些函数映射到哪些API端点。从端点返回的JSON只涉及设置路由以及经由Python标准库json.dumps函数返回的数据。对异步的支持还没有在Falcon中实现,但是正在努力在Falcon 3.0中实现。
Falcon还采用了健全的开箱即用的默认设置,所以安装时不需要什么修改。例如,对于没有显式声明的任何路由,默认情况下都会引发404s。如果希望向客户机返回错误,可以抛出与框架捆绑在一起的大量常规异常(如HTTPBadRequest)中的一个,或者使用通用的falcon.HTTPError异常。如果需要对路由进行预处理或后处理,Falcon也为它们提供了钩子。
Falcon对APIs的关注意味着这里很少有使用传统HTML用户界面构建web应用程序的内容。例如,不要对表单处理函数和CSRF保护工具抱有太多期望。但是,Falcon提供了优雅的选项来扩展其功能,因此可以构建更复杂的项目。除了上述钩子机制之外,您还可以找到一个用于创建中间件的接口,该接口可用于包装所有Falcon的APIs。
与其他框架相比,Falcon的文档比较少,但这只是因为覆盖的内容比较少。用户指南包括对所有主要特性的正式的逐步演示,以及快速启动部分,允许您查看有或没有注释的样例代码。
示例代码如下:
class QuoteResource:
def on_get(self, req, resp):
"""Handles GET requests"""
quote = {
'quote': (
"I've always been more interested in "
"the future than in the past."
),
'author': 'Grace Hopper'
}
resp.media = quote
api = falcon.API()
api.add_route('/quote', QuoteResource())
FastAPI(
https://fastapi.tiangolo.com/)的名称很好地总结了它所做的事情。它被构建为快速创建API端点而服务,且运行速度也很快。
FastAPI利用Starlette项目作为其高速网络核心,但是要使用FastAPI,您不需要了解Starlette的内部原理。定义端点的方式与Flask或Bottle应用程序非常相似——使用装饰器(decorator)来指明哪个函数处理哪个路由——然后返回自动转换成JSON的字典。
您可以很容易地重写返回内容的方式。例如,如果希望从某些端点返回HTML/XML,只需返回一个自定义响应对象即可。如果您想要添加自定义中间件,您可以弹出任何遵循ASGI标准的内容。
FastAPI使用Python的类型提示来提供路由所接受的数据类型的约束。例如,如果您有一个类型为Optional[int]的路由,FastAPI将拒绝除整数以外的所有提交。你不需要添加数据校验代码到你的端点,可以只使用类型提示,然后让FastAPI来完成这项工作。
当然,有些东西被省略了。例如,没有原生HTML模板引擎,但并不缺少填补这一空白的第三方解决方案。数据库连接也是如此,但是文档中包含了关于如何协同某些ORMs(例如Peewee)使用FastAPI的异步行为而工作的细节。
示例代码如下:
from typing import Optional
from fastapi import FastAPI
App = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Optional[str] = None):
return {"item_id": item_id, "q": q}
许多关于Python web框架的讨论都从Flask(http://flask.pocoo.org/)开始,这是有原因的。Flask构建良好,易于理解的框架,很容易使用并且很稳定。在轻量级web项目或基本REST API中使用Flask几乎是不可能出错的,但是如果您试图构建任何更大的东西,你将会面临很大的负担。
Flask的主要吸引力在于它的低门槛。一个基本的“hello world”应用程序可以用不到10行Python代码完成。Flask包含了一个广泛使用的HTML模板系统Jinja2,它可以使文本的渲染更加容易,但是Jinja2可以被替换为任意数量的其他模板引擎(比如Mustache:
https://github.com/defunkt/pystache),或者您也可以使用自己的模板引擎。
Flask版Hello World 应用:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
把这个保存为hello.py或其它不是flask.py的文件,然后就可以按照一定的模式来运行程序了:
$ export FLASK_APP=hello.py
$ flask run
* Running on http://127.0.0.1:5000/
或者在windows下
命令行窗口:C:pathtoapp>set FLASK_APP=hello.py
Powershell:PS C:pathtoapp> $env:FLASK_APP = "hello.py"
或者可以使用 python -m flask:
$ export FLASK_APP=hello.py
$ python -m flask run
* Running on http://127.0.0.1:5000/
(详情可以参考官网进一步了解)
出于简单性的考虑,Flask省略了一些细节,比如数据层或者ORM,并且没有提供类似表单验证的功能。然而,Flask可通过扩展支持机制进行扩展,已有的扩展有几十个,覆盖了许多常见的用例场景,比如缓存,表单处理和验证,以及数据库连接。这种缺省设计允许你以绝对最小的功能开始设计一个Flask应用程序,然后在你需要的时候将它们分层。
Flask的文件是亲切和容易阅读。快速开始文档很好地帮助您入门,同时还解释了简单的Flask应用程序的默认选择的重要性,并且API文档中有很多很好的例子。同样优秀的还有Flash示例片段的集合,是一些如何完成特定任务的快速而粗糙的示例,例如,如果对象存在如何返回,或者如果对象不存在,如何返回404错误。
在2018年,Flask发布了具有里程碑意义的1.0版本,其中Python 2.6和Python 3.3是最小的支持版本,并且它的许多行为最终都是固定不变的。Flask不显式地支持Python的异步语法,但是一个API兼容的Flask变体Quart已经被分离出来以满足这个需求。
小巧轻便的Pyramid(https://trypyramid.com/)非常适合于一些这样的任务,比如将现有的Python代码作为REST API公开,或者为开发人员承担大部分繁重工作的web项目提供核心支持。
“Pyramid会让你迅速变得富有成效,并与你一起成长,”文档简述中说。“当你的应用程序很小的时候,它不会阻碍你;当你的应用程序变大的时候,它也不会妨碍你。”
描述Pyramid的极简主义的一个好方法是“不受策略约束”,在文档中讨论Pyramid如何与其他web框架相比较的部分使用了这个术语。基本上,“无策略”意味着您选择使用哪种数据库或哪种模板语言不是Pyramid所关心的。
建立一个基本的Pyramid应用程序需要非常少的工作。与Bottle和Flask一样,除了框架本身的文件外,Pyramid应用程序可以由单个Python文件组成。一个简单的单路由API只需要十来行代码。大部分都是样板文件,比如…import语句和设置WSGI服务器。
默认情况下,Pyramid包括一些在web应用程序中常见的事项,但它们是作为组件提供的,并将其拼接在一起,而不是作为成熟的解决方案。例如,对用户会话的支持甚至附带了CSRF保护。但对用户帐户的支持,如登录或帐户管理,不在处理的一部分。你必须自己处理它或通过插件来添加支持它。表单处理和数据库连接也是如此。
Pyramid甚至提供了一种从以前的Pyramid项目创建模板的方法来重用以前的工作。这些被称为“脚手架”的模板生成了一个金字塔应用程序,具有简单的路由和一些初始HTML/css模板。捆绑的脚手架包括一个示例启动程序项目和一个通过流行的Python库SQLAlchemy(
http://www.sqlalchemy.org/)连接到数据库的项目。
Pyramid体贴入微的测试和调试工具提供了优秀的功能。在Pyramid应用程序中捆绑debugtoolbar扩展组件,你可在每个网页上得到一个可点击的图标,它会生成应用程序执行的详细信息,包括发生错误时的详细回溯。还提供了日志记录和单元测试。
Pyramid的文件是优秀的。除了对基础知识的快速浏览和教程风格的演练外,还可以找到一组社区贡献的教程和一本常见食谱式的“烹饪指南”书。后者包括了针对一系列目标环境的部署技术,从谷歌App Engine到Nginx。
Pyramid同时支持python2和python3,但是不使用python3的异步语法。如果想在Pyramid中利用异步,请参阅aiopyramid项目,它包括一个用于异步驱动的“hello world”应用程序的脚手架。
应用示例代码如下:
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
def hello_world(request):
return Response('Hello World!')
if __name__ == '__main__':
with Configurator() as config:
config.add_route('hello', '/')
config.add_view(hello_world, route_name='hello')
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 6543, app)
server.serve_forever()
Sanic为快速和简单而设计,与Python 3.6或更高版本一起工作,并使用Python的async/await语法(从Python 3.5开始可用)来让您创建高效的web应用程序。
与Flask或Bottle一样,一个基础的Sanic程序“hello world”大约需要运行10行代码,其中大部分是导入和其他样板文件。关键的区别是,应用程序路由必须声明为异步定义函数(async def functions),并且必须在异步代码中使用await来调用这些函数。如果您以前编写过异步驱动的应用程序,那么你应已经掌握了最困难的部分。
Sanic用于处理连接和响应的许多机制大家都很熟悉。请求和响应只是具有相似属性的对象,比如上传的文件、表单、JSON对象、头等等。
具有许多路由的应用程序变得难以管理。Sanic用“蓝图(blueprints)”来解决这个问题,这些对象可以描述一组路由,并允许你通过高级界面来管理它们。不用显式地编写每个路由,也不用使用过多的带变量的路由,你可以编写一些蓝图来描述路由在你的应用程序中是如何工作的(例如,/object/object_id/action)。蓝图可以有通用的中间件,如果您想将管理功能应用到某些路由而不是其他路由,那么这是非常有用的。
Sanic还可以处理HTTP以外的协议。WebSocket端点只需要不同的装饰器和更多的内部逻辑(例如,等待和处理响应)。可以通过子类化asyncio.protocol来支持自定义网络协议。
Sanic故意省略了数据库连接和HTML模板等功能,而保留了用于插入这些功能的特性:中间件、集中式应用配置,等等。
示例代码如下:
from sanic import Sanic
from sanic.response import json
app = Sanic("App Name")
@app.route("/")
async def test(request):
return json({"hello": "world"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Tornado(
http://www.tornadoweb.org/)是另一个针对特定用例的微型框架:异步网络应用程序。Tornado非常适合创建那些打开大量网络连接并使其保持活力的服务——即任何涉及WebSockets或长轮询的服务。Tornado 6.0需要Python 3.5或更高版本,完全不支持Python 2。
像Bottle 或 Falcon一样,Tornado忽略了与它的中心目的无关的特征。Tornado有一个用于生成HTML和其他输出的内置模板系统,并提供了用于国际化、表单处理、cookie设置、用户身份验证和CSRF保护的机制。但是它忽略了一些主要用于面向用户的web应用程序的特性,比如表单验证和ORM。
Tornado擅长为需要对异步网络进行严密控制的应用程序提供基础设施。例如,Tornado不仅提供一个内置的异步HTTP服务器,而且还提供一个异步HTTP客户机。因此,Tornado非常适合构建并行查询其他站点并对返回的数据进行操作的应用程序,例如网络爬虫或网络机器人(web scraper或bot)。
如果您想创建一个使用HTTP以外的协议的应用程序,Tornado已经为您提供了帮助。Tornado提供对诸如DNS解析器等实用程序的低级TCP连接和套接字的访问,以及对第三方认证服务的访问,它还通过WSGI标准支持与其他框架的互操作。文档虽小但并不稀疏宽泛,其中包含了实现所有这些特性的丰富示例。
Tornado利用并补充了Python用于异步行为的本机功能。如果您使用的是Python 3.5, Tornado支持内置的async和await关键字,这可以提高应用程序的速度。您还可以使用futures或回调来处理对事件的响应。
Tornado提供了一个同步原语库(信号量、锁等)来协调异步协程之间的事件。请注意,Tornado通常运行为单线程模式,因此这些原语与它们的线程名称不同。但是,如果您希望在并行进程中运行Tornado以利用多个套接字和内核,那么可以使用一些工具来实现这一点。
Tornado的文档涵盖了框架中的每个主要概念以及模型中的所有主要api。尽管它包含一个示例应用程序(一个web爬虫),但它主要用于演示Tornado的排队模块。
应用示例代码如下:
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
另外,相比前面小而美的框架较而言,Django(
https://www.djangoproject.com/)是个完整的技术栈了,基本有各种支持,悠久而庞大,这里没有提出来更多介绍。概而言之,Django是一个高级Python Web框架,它鼓励快速开发和干净、实用的设计。它由经验丰富的开发人员构建,解决了Web开发中的许多麻烦,因此您可以专注于编写应用程序,而无需重新发明轮子。它是免费和开源的,学习曲线相对来说较高,有兴趣的可以去官网详细研究一下。