PYTHON优秀源码分析

webpy源码分析(一):application的__init_

2018-04-08  本文已影响0人  WillCheng

本文通过分析webpy代码学习python编程技巧、系统设计以及web编程的基本方法
我是边看代码代码边写此文的,所以代码中的有些问题可能会放在后序的文章中详细阐述。

webpy简单介绍

webpy是个使用python编写的轻量级web服务器

相关资料

webpy源码
webpy官网

测试用代码

# test_webpy.py
import web  #指向源码中的web目录
        
urls = (
    '/(.*)', 'hello'  
)
app = web.application(urls, globals()) # 初始化

class hello:        
    def GET(self, name):
        if not name: 
            name = 'World'
        return 'Hello, ' + name + '!'

if __name__ == "__main__":
    app.run()           #启动

运行结果

服务端:


123.png
2. web.config
123.png
3. handle_with_processors()与self.processor[]

其作用为在响应每个http请求前后做一些额外处理。此处先不关注processor具体是什么,只关注这些processor是如何注入的,你可以把这种方式作为一种设计模式来理解。(作者认为所有设计模式的目的只有一个:解耦)。

我在每个processor以及http请求处理函数中增加了一条日志,额外增加了一个unload test的processor,后面会提供代码。先来看看执行结果,注意执行顺序:


123.png

再来看看代码:


123.png

图注:

  1. 初始化
  1. 为其中一个load processor的内容,参考用

  2. loadhook()和unloadhook()
    这两个辅助函数用于注册processor用。

4.实际执行processor的地方

此设计模式总结:

  1. 适用性

2.伪代码
基础代码:

def 外部接口(请求参数):
    return 第三方处理函数(请求参数)  

应用该设计模式以后:

def 外部接口(请求参数):
    预处理逻辑一(请求参数)
    预处理逻辑二(请求参数)
     ...
    结果 = 第三方处理函数(请求参数)  

    结果 = 再处理逻辑一(请求参数,上一步结果)
    结果 = 再处理逻辑二(请求参数,上一步结果)
     ...
    return 结果
3. mapping和fvars

此为__init()__的第二、第三个参数,其与webpy框架的使用方法有很大的关系。
先来修改下测试代码:

import web

class hello:
    def __init__(self):
        self.str = 'I am %s\n' % self.__class__.__name__

    def GET(self, *args):
        self.str += 'args len is %d(%s)' % (len(args), args)
        return self.str

class hello2(hello):
    pass

urls = (
        '/hello', r'hello',
        '/hello_cls', hello,
        '/hello_arg/(\w*)', r'hello',
        '/hello_arg/(\w*)/(\w*)', r'hello',
        '/\w*', r'hello2',

        '/1/(\w*)', r'\1',
        '/2/(\w*)/(\w*)', r'\1',
        '/3/(\w*)/(\w*)/(\w*)', r'\1\2',

        '/4/hello_redi', r'redirect /2/hello/redi',
        )
app = web.application(urls, globals())

if __name__ == "__main__":
    app.run()

定义两个类hello和hello2(继承自hello),__init__的逻辑用来区分我是hello还是hello2,GET函数用来打印传进来的参数。
在urls中定义了更多的条目用来进行测试,其中条目是两两成对的,前者表示url请求,后者表示对应的处理方式。webpy会按顺序查找urls中的条目,如果找到则停止查找并进行处理。
接下来我们对每一对条目进行解释:

/hello_arg/用来对应到hello类,而括号中的内容将作为参数传递给处理逻辑

多个参数的情况,注意querystring不会作为参数传递

image.png

根据访问请求指定处理的类名,并且会作为参数传递

接下来我们看看webpy代码的实现:

123.png

图注:

  1. 在初始化时传给application的第二个参数主要用于符号的查找。具体的使用看箭头的指向,fvars储存的就是globals(),从中可以找到hello类等符号
  2. mapping存放的就是对照表,也就是urls中的内容。在初始化的时候将其进行了两两分组
  3. 在之前讲到processor的时候,我们有提过handle(),它负责处理http请求。其中self._match()用于查找mapping,获得具体处理的对象(fn),以及URI相关信息(args);self._delegate()则负责执行处理逻辑
  4. re_subm的实现可以看一下其__doc__中的举例
  5. cls = fvars[f]这行代码在实际运行过程中可能会有问题,当cls不存在时后端会直接抛出异常在浏览器中看到500的错误
4. reload mod功能

__init__()最后一个参数表示是否开启reload的功能。reload功能指无需重启后端服务就可以修改http处理逻辑并使之生效。包括对照表urls和对应的处理逻辑(比如hello类)

123.png

图注:

  1. 通过注册两个processor,在每次响应http请求前进行mod是否更新的检查(Reloader)以及mapping与fvars的更新(reload_mapping)。注意, main模块是不能reload的,所以在__init__中将其作为一个非main模块重新import。相关的代码有一些问题,我做了一些调整,见图
  2. Reloader()检查所有mod的时间戳是否有变化,并reload有变化的mod。但是已经被引用的mod除非重新赋值引用其的变量,否则无法更新。个人认为从性能考虑,只用检查application对应的mod,其他的可以忽略。如果使用python3执行代码,需要将765的代码改成:
except Exception as e:

下一篇

webpy源码分析(二): application的run()

上一篇 下一篇

猜你喜欢

热点阅读