这篇文章主要介绍了Python的web.py框架下的application.py模块,作者深入分析了web.py的源码,需要的朋友可以参考下
本文主要分析的是web.py库的application.py这个模块中的代码。总的来说,这个模块主要实现了WSGI兼容的接口,以便应用程序能够被WSGI应用服务器调用。WSGI是Web Server Gateway Interface的缩写,具体细节可以查看WSGI的WIKI页面
接口的使用
使用web.py自带的HTTP Server
下面这个例子来自官方文档的Hello World,这个代码一般是应用入口的代码:
?
1 2 3 4 5 6 7 8 9 10 11 import web urls = ("/.*", "hello") app = web.application(urls, globals()) class hello: def GET(self): return 'Hello, world!' if __name__ == "__main__": app.run()上面的例子描述了一个web.py应用最基本的组成元素:
URL路由表
一个web.application实例app
调用app.run()
其中,app.run()的调用是初始化各种WCGI接口,并启动一个内置的HTTP服务器和这些接口对接,代码如下:
?
1 2 def run(self, *middleware): return wsgi.runwsgi(self.wsgifunc(*middleware))与WSGI应用服务器对接
如果你的应用要与WSGI应用服务器对接,比如uWSGI,gunicorn等,那么应用入口的代码就要换一种写法了:
?
1 2 3 4 5 6 7 8 9 import web class hello: def GET(self): return 'Hello, world!' urls = ("/.*", "hello") app = web.application(urls, globals()) application = app.wsgifunc()在这种场景下,应用的代码不需要启动HTTP服务器,而是实现一个WSGI兼容的接口供WSGI服务器调用。web.py框架为我们实现了这样的接口,你只需要调用application = app.wsgifunc()就可以了,这里所得到的application变量就是WSGI接口(后面分析完代码你就会知道了)。
WSGI接口的实现分析
分析主要围绕着下面两行代码进行:
?
1 2 app = web.application(urls, globals()) application = app.wsgifunc()web.application实例化
初始化这个实例需要传递两个参数:URL路由元组和globals()的结果。
另外,还可以传递第三个变量:autoreload,用来指定是否需要自动重新导入Python模块,这在调试的时候很有用,不过我们分析主要过程的时候可以忽略。
application类的初始化代码如下:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 class application: def __init__(self, mapping=(), fvars={}, autoreload=None): if autoreload is None: autoreload = web.config.get('debug', False) self.init_mapping(mapping) self.fvars = fvars self.processors = [] self.add_processor(loadhook(self._load)) self.add_processor(unloadhook(self._unload)) if autoreload: ...其中,autoreload相关功能的代码略去了。其他的代码主要作了如下几个事情:
self.init_mapping(mapping):初始化URL路由映射关系。
self.add_processor():添加了两个处理器。
初始化URL路由映射关系
?
1 2 def init_mapping(self, mapping): self.mapping = list(utils.group(mapping, 2))这个函数还调用了一个工具函数,效果是这样的:
?
1 2 3 urls = ("/", "Index", "/hello/(.*)", "Hello", "/world", "World")如果用户初始化时传递的元组是这样的,那么调用init_mapping之后:
?
1 2 3 self.mapping = [["/", "Index"], ["/hello/(.*)", "Hello"], ["/world", "World"]]后面框架在进行URL路由时,就会遍历这个列表。
添加处理器
?
1 2 self.add_processor(loadhook(self._load)) self.add_processor(unloadhook(self._unload))这两行代码添加了两个处理器:self._load和self._unload,而且还对这两个函数进行了装饰。处理器的是用在HTTP请求处理前后的,它不是真正用来处理一个HTTP请求,但是可以用来作一些额外的工作,比如官方教程里面有提到的给子应用添加session的做法,就是使用了处理器:
?
1 2 3 4 def session_hook(): web.ctx.session = session app.add_processor(web.loadhook(session_hook))处理器的定义和使用都是比较复杂的,后面专门讲。
wsgifunc函数
wsgifunc的执行结果是返回一个WSGI兼容的函数,并且该函数内部实现了URL路由等功能。
?
1 2 3 4 5 6 7 def wsgifunc(self, *middleware): """Returns a WSGI-compatible function for this application.""" ... for m in middleware: wsgi = m(wsgi) return wsgi除开内部函数的定义,wsgifunc的定义就是这么简单,如果没有实现任何中间件,那么就是直接返回其内部定义的wsgi函数。
wsgi函数
该函数实现了WSGI兼容接口,同时也实现了URL路由等功能。
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 def wsgi(env, start_resp): # clear threadl