Considering only simple path mappings, some simple regular expressions are involved. The mapping in web.py uses a list, and each mapping has two elements. For the convenience of writing code, use a dictionary directly. Before we start the content, let's do some homework.
globals trick
Give you a name, how to check if there is a class with the same name and then create an instance?
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)
In Python, every time you define a class and add a variable, a name mapping will be added globally for easy lookup during execution. Use globals() to return all names and corresponding objects contained in the current code. So g['TestA']() and TestA() are equivalent. And TestB returns None because there is no such class globally. inspect.isclass is to judge whether a variable is a class.
URL parsing
The standard format of the URL is as follows. The urllib library of Python provides the urlparse function to help us quickly parse the 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)
After execution, you can see the information of each part as follows:
scheme: http
netloc: www.xyz.com
path: /abc/def
params: params
query: a=1&b=2&c=zzz
fragment: fragment
regular expression match
In mapping, we define the rules for path matching, and the specific implementation is to use regular expression matching. web.py is designed with efficiency in mind, and caches the matching of regular expressions. The specific implementation can be seen in the implementation of the Memoize class in the source code utils.py. Let's simplify the code here, assuming that the mapping is ('^/index/name=(.*)&age=(.*)$', 'index'), and the path entered now is /index/name=ZV&age=18. We can complete path matching and obtain parameters through the following code.
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()]))
Program execution result:
Class:index Args: ['ZV', '18']
After understanding these prerequisites, in the next chapter we will add URL mapping functionality to the framework.