只考虑简单的路径映射,会涉及到一些简单的正则表达式。web.py里映射用的是列表,每个映射两个元素,为了写代码简便,直接用字典好了。在开始内容之前,我们先做些准备工作。
globals的花招
给你一个名字,如何查看有没有同名的类然后再创建一个实例?
import inspect
class TestA:
def info(self):
print('TestA')
def create(cls_name):
g = globals()
if cls_name in g:
if inspect.isclass(g[cls_name]):
return g[cls_name]()
return None
ta = create('TestA')
tb = create('TestB')
ta.info()
print(tb)
在Python里你每定义一个类,添加一个变量,就会在全局增加一个名字映射,方便执行的时候查找。用globals()可以返回当前代码里包含的所有名字及对应的对象。所以g['TestA']()和TestA()是等价的。而TestB因为全局没有这个类所以返回None。inspect.isclass是判断某个变量是不是类。
URL解析
URL的标准格式如下,Python的urllib库提供了urlparse函数帮助我们快速解析URL。
from urllib.parse import urlparse
url = 'http://www.xyz.com/abc/def;params?a=1&b=2&c=zzz#fragment'
p = urlparse(url)
print('scheme: ' + p.scheme)
print('netloc: ' + p.netloc)
print('path: ' + p.path)
print('params: ' + p.params)
print('query: ' + p.query)
print('fragment: ' + p.fragment)
执行后,可以看到各部分信息如下:
scheme: http
netloc: www.xyz.com
path: /abc/def
params: params
query: a=1&b=2&c=zzz
fragment: fragment
正则表达式匹配
在mapping里我们定义了路径匹配的规则,具体实现是使用正则表达式匹配。web.py在设计的时候考虑到效率,针对正则表达式的匹配进行了缓存处理。具体实现可以看源代码utils.py里Memoize类的实现。我们在这里简化一下代码,假设mapping为('^/index/name=(.*)&age=(.*)$', 'index'),现在输入的路径是/index/name=ZV&age=18。我们可以通过以下代码完成路径匹配并获得参数。
import re
class proxy:
def __init__(self):
self.match = None
def __call__(self, match):
self.match = match
def match(pattern, cls, value):
p = proxy()
compiled = re.compile(pattern)
compiled.sub(p.__call__, value)
cls, args = compiled.sub(cls, value), p.match
return cls, args
if __name__ == '__main__':
pattern = '/index/name/(.*)/age/(.*)'
cls = 'index'
value = '/index/name/ZV/age/18'
cls, args = match(pattern, cls, value)
print('Class:' + cls)
if args:
print('Args: ' + str([x for x in args.groups()]))
程序执行结果:
Class:index Args: ['ZV', '18']
在了解了这些预备知识后,在下一章我们就会为框架添加URL映射功能。