python读取application_【Python】【Web.py】详细解读
Pytho。。。
详细解读Python的web.py框架下的application.py模块
这篇⽂章主要介绍了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,这个代码⼀般是应⽤⼊⼝的代码:
上⾯的例⼦描述了⼀个web.py应⽤最基本的组成元素:
URL路由表
⼀个web.application实例app
调⽤app.run()
其中,app.run()的调⽤是初始化各种WCGI接⼝,并启动⼀个内置的HTTP服务器和这些接⼝对接,代码如下:
与WSGI应⽤服务器对接
如果你的应⽤要与WSGI应⽤服务器对接,⽐如uWSGI,gunicorn等,那么应⽤⼊⼝的代码就要换⼀种写法了:
在这种场景下,应⽤的代码不需要启动HTTP服务器,⽽是实现⼀个WSGI兼容的接⼝供WSGI服务器调⽤。web.py框架为我们实现了这样的接⼝,你只需要调⽤application
= app.wsgifunc()就可以了,这⾥所得到的application变量就是WSGI接⼝(后⾯分析完代码你就会知道了)。
WSGI接⼝的实现分析
分析主要围绕着下⾯两⾏代码进⾏:
web.application实例化
初始化这个实例需要传递两个参数:URL路由元组和globals()的结果。
另外,还可以传递第三个变量:autoreload,⽤来指定是否需要⾃动重新导⼊Python模块,这在调试的时候很有⽤,不过我们分析主要过程的时候可以忽略。
application类的初始化代码如下:
其中,autoreload相关功能的代码略去了。其他的代码主要作了如下⼏个事情:
self.init_mapping(mapping):初始化URL路由映射关系。
self.add_processor():添加了两个处理器。
初始化URL路由映射关系
这个函数还调⽤了⼀个⼯具函数,效果是这样的:
如果⽤户初始化时传递的元组是这样的,那么调⽤init_mapping之后:
后⾯框架在进⾏URL路由时,就会遍历这个列表。
添加处理器
这两⾏代码添加了两个处理器:self._load和self._unload,⽽且还对这两个函数进⾏了装饰。处理器的是⽤在HTTP请求处理前后的,它不是真正⽤来处理⼀个HTTP请求,但是可以⽤来作⼀些额外的⼯作,⽐如官⽅教程⾥⾯有提到的给⼦应⽤添加session的做法,就是使⽤了处理器:
处理器的定义和使⽤都是⽐较复杂的,后⾯专门讲。
wsgifunc函数
wsgifunc的执⾏结果是返回⼀个WSGI兼容的函数,并且该函数内部实现了URL路由等功能。
除开内部函数的定义,wsgifunc的定义就是这么简单,如果没有实现任何中间件,那么就是直接返回其内部定义的wsgi函数。
wsgi函数
该函数实现了WSGI兼容接⼝,同时也实现了URL路由等功能。
下⾯来仔细分析⼀下这个函数:
self._cleanup()内部调⽤utils.ThreadedDict.clear_all(),清除所有的thread local数据,避免内存泄露(因为web.py框架的很多数据都会保存在thread local变量中)。
self.load(env)使⽤env中的参数初始化变量,这些变量涵盖了当前请求的信息,我们在应⽤中有可能会使⽤到,⽐如
这⼀段主要是调⽤self.handle_with_processors(),这个函数会对请求的URL进⾏路由,到合适的类或⼦应⽤来处理该请求,也会调⽤添加的处理器来做⼀些其他⼯作(关于处理器的部分,后⾯专门讲)。对于处理的返回结果,可能有三种⽅式:
返回⼀个可迭代对象,则进⾏安全迭代处理。
返回其他值,则创建⼀个列表对象来存放。
如果抛出了⼀个HTTPError异常(⽐如我们使⽤raise web.OK("hello, world")这种⽅式来返回结果时),则将异常中的数据e.data封装成⼀个列表。
-
接下来的这段代码,会对前⾯返回的列表result进⾏字符串化处理,得到HTTP Response的body部分。然后根据WSGI的规范作如下两个事情:
调⽤start_resp函数。
将result结果转换成⼀个迭代器。
现在你可以看到,之前我们提到的application = app.wsgifunc()就是将wsgi函数赋值给application变量,这样应⽤服务器就可以采⽤WSGI标准和我们的应⽤对接了。
处理HTTP请求
前⾯分析的代码已经说明了web.py框架如何实现WSGI兼容接⼝的,即我们已经知道了HTTP请求到达框架以及从框架返回给应⽤服务器的流程。那么框架内部是如何调⽤我们的应⽤代码来实现⼀个请求的处理的呢?这个就需要详细分析刚才忽略掉的处理器的添加和调⽤过程。
loadhook和unloadhook装饰器
这两个函数是真实处理器的函数的装饰器函数(虽然他的使⽤不是采⽤装饰器的@操作符),装饰后得到的处理器分别对应请求处理之前(loadhook)和请求处理之后(unloadhook)。
loadhook
这个函数返回⼀个函数processor,它会确保先调⽤你提供的处理器函数h,然后再调⽤后续的操作函数handler。
unloadhook
这个函数也返回⼀个processor,它会先调⽤参数传递进来的handler,然后再调⽤你提供的处理器函数。
handle_with_processors函数
这个函数挺复杂的,最核⼼的部分采⽤了递归实现(我感觉不递归应该也能实现同样的功能)。为了说明清晰,采⽤实例说明。
前⾯有提到,初始化application实例的时候,会添加两个处理器到self.processors:
所以,现在的self.processors是下⾯这个样⼦的:
# 为了⽅便后续说明,我们缩写⼀下:
当框架开始执⾏handle_with_processors的时候,是逐个执⾏这些处理器的。我们还是来看代码分解,⾸先简化⼀下
handle_with_processors函数:
函数执⾏的起点是位置1,调⽤其内部定义函数process(processors)。
如果位置2判断处理器列表不为空,则进⼊if内部。
在位置3调⽤本次需要执⾏的处理器函数,参数为⼀个lambda函数,然后返回。
如果位置2判断处理器列表为空,则执⾏self.handle(),该函数真正的调⽤我们的应⽤代码(下⾯会讲到)。
以上⾯的例⼦来说,⽬前有两个处理器:
从位置1进⼊代码后,在位置2会判断还有处理器要执⾏,会⾛到位置3,此时要执⾏代码是这样的:
load_processor函数是⼀个经过loadhook装饰的函数,因此其定义在执⾏时是这样的:
会先执⾏self._load(),然后再继续执⾏process函数,依旧会⾛到位置3,此时要执⾏的代码是这样的:
unload_processor函数是⼀个经过unloadhook装饰的函数,因此其定义在执⾏时是这样的:
现在会先执⾏process([])函数,并且⾛到位置4(调⽤self.handle()的地⽅),从⽽得到应⽤的处理结果,然后再调⽤本处理器的处理函数self._unload()。
总结⼀下执⾏的顺序:
如果还有更多的处理器,也是按照这种⽅法执⾏下去,对于loadhook装饰的处理器,先添加的先执⾏,对于unloadhook装饰的处理器,后添加的先执⾏。
handle函数
讲了这么多,才讲到真正要调⽤我们写的代码的地⽅。在所有的load处理器执⾏完之后,就会执⾏self.handle()函数,其内部会调⽤我们写的应⽤代码。⽐如返回个hello, world之类的。self.handle的定义如下:
这个函数就很好理解了,第⼀⾏调⽤的self._match是进⾏路由功能,到对应的类或者⼦应⽤,第⼆⾏的self._delegate就是调⽤这个类或者传递请求到⼦应⽤。
_match函数
_match函数的定义如下:
该函数的参数中mapping就是self.mapping,是URL路由映射表;value则是path,是本次请求路径。该函数遍历
self.mapping,根据映射关系中处理对象的类型来处理:
位置1,处理对象是⼀个application实例,也就是⼀个⼦应⽤,则返回⼀个匿名函数,该匿名函数会调⽤self._delegate_sub_application 进⾏处理。
位置2,如果处理对象是⼀个字符串,则调⽤_subm进⾏处理,这⾥会把value(也就是path)中的和pat匹配的部分替换成what(也就是我们指定的⼀个URL模式的处理对象字符串),然后返回替换后的结果以及匹配的项(是⼀个re.MatchObject实例)。
位置3,如果是其他情况,⽐如直接指定⼀个类对象作为处理对象。
如果result⾮空,则返回处理对象和⼀个参数列表(这个参数列表就是传递给我们实现的GET等函数的参数)。
_delegate函数
从_match函数返回的结果会作为参数传递给_delegate函数:
其中:
fn:是要处理当前请求的对象,⼀般是⼀个类名。
args:是要传递给请求处理对象的参数。
self.fvars:是实例化application时的全局名称空间,会⽤于查处理对象。
_delegate函数的实现如下:python怎么读取py文件
这个函数主要是根据参数f的类型来做出不同的处理:
f为空,则返回302 Not Found.
f是⼀个application实例,则调⽤⼦应⽤的handle_with_processors()进⾏处理。
f是⼀个类对象,则调⽤内部函数handle_class。
f是⼀个字符串,则进⾏重定向处理,或者获取要处理请求的类名后,调⽤handle_class进⾏处理(我们写的代码⼀般是在这个分⽀下被调⽤的)。
f是⼀个可调⽤对象,直接调⽤。
其他情况返回302 Not Found.
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论