在上一篇日志中已经讨论和实现了根据url执行相应应用,在我阅读了bottle.py官方文档后,按照bottle的设计重写一遍,主要借鉴大牛们的设计思想。
一个bottle.py的简单实例
来看看bottle是如何使用的,代码来自http://www.bottlepy.org/docs/0.12/index.html:
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)
很显然,bottle是使用装饰器来路由的。根据bottle的设计,我来写一个简单的框架。
Python装饰器
装饰器,顾名思义就是包装一个函数。在不改变函数的同时,动态的给函数增加功能。这里不在探讨更多的细节。
大致的框架
根据WSGI的定义,一个WSGI应用必须要是可调用的。所以下面是一个WSGI应用的大致框架:
class WSGIapp(object): def __init__(self): pass def route(self,path=None): pass def __call__(self,environ,start_response): return self.wsgi(environ,start_response) def wsgi(self,environ,start_response): pass
其中,route方法就是来保存url->target的。这里为了方便,将url->target保存在字典中:
def route(self,path=None): def decorator(func): self.routes[path] = func return func return decorator
这里return func注释掉也可以,求大神解释一下啊!!
然后就是实现WSGIapp的每个方法:
class WSGIapp(object): def __init__(self): self.routes = {} def route(self,path=None): def decorator(func): self.routes[path] = func return func return decorator def __call__(self,environ,start_response): print 'call' return self.wsgi(environ,start_response) def wsgi(self,environ,start_response): path = environ['PATH_INFO'] print path if path in self.routes: status = '200 OK' response_headers = [('Content-Type','text/plain')] start_response(status,response_headers) print self.routes[path]() return self.routes[path]() else: status = '404 Not Found' response_headers = [('Content-Type','text/plain')] start_response(status,response_headers) return '404 Not Found!' app = WSGIapp() @app.route('/') def index(): return ['This is index'] @app.route('/hello') def hello(): return ['hello'] from wsgiref.simple_server import make_server httpd = make_server('',8000,app) print 'start....' httpd.serve_forever()
这样,一个简易的web框架的雏形就实现了,如果对装饰器中的路径加入正则表达式,那么就可以很轻松的应对URL了。下一篇日志就是加入模板引擎jinja2了。