让我们扫一眼上次我们写的简单NotFlask类。
class NotFlask():
def __init__(self):
self.routes = {}
def route(self, route_str):
def decorator(f):
self.routes[route_str] = f
return f
return decorator
def serve(self, path):
view_function = self.routes.get(path)
if view_function:
return view_function()
else:
raise ValueError('Route "{}"" has not been registered'.format(path))
app = NotFlask()
@app.route("/")
def hello():
return "Hello World!"
现在我们有一个新的改进方法用来匹配输入的路径,我们打算移除我们上一个版本实现时用到的原生字典。
让我们从改造我们的函数着手,以便于添加路径,这样我们就可以用(pattern, view_function)对列表代替字典保存我们的路径。
这意味着当一个程序员使用@app.route()装饰一个函数,我们将要尝试将他们的路径编译变成一个正则表达式,然后存储它,属于一个在我们新的路径列表里的装饰函数。
让我们看看实现代码:
class NotFlask():
def __init__(self):
self.routes = []
#Here's our build_route_pattern we made earlier
@staticmethod
def build_route_pattern(route):
route_regex = re.sub(r'()', r'(?P\1.+)', route)
return re.compile("^{}$".format(route_regex))
def route(self, route_str):
def decorator(f):
#Instead of inserting into a dictionary,
#We'll append the tuple to our route list
route_pattern = self.build_route_pattern(route_str)
self.routes.append((route_pattern, f))
return f
return decorator
我们也打算需要一个get_route_match方法,给它一个路径实例,将会尝试并找到一个匹配的view_function,或者返回None如果一个也找不到的话。
然而,如果找了到匹配的话,除了view_function之外,我们还需要返回一个东西,那就是我们包含之前捕获匹配组的字典,我们需要它来为视图函数传递正确的参数。
好了我们的get_route_match大概就长这样:
def get_route_match(path):
for route_pattern, view_function in self.routes:
m = route_pattern.match(path)
if m:
return m.groupdict(), view_function
return None
现在我们快要完成了,最后一步将是找出调用view_function的方法,使用来自正则表达式匹配组字典的正确参数。
调用一个函数的若干种方法
让我们回顾一下不同的方法调用一个python的函数。
比如像这样:
def hello_user(username):
return "Hello {}!".format(username)
最简单的(也许正是你所熟知的)办法是使用正则参数,在这里参数的顺序匹配我们定义的那些函数的顺序。
>>> hello_user("ains")
Hello ains!
另一种方法调用一个函数是使用关键词参数。关键词参数可以通过任何顺序指定,适合有许多可选参数的函数。
>>> hello_user(username="ains")
Hello ains!
在Python中最后一种调用一个函数的方法是使用关键词参数字典,字典中的关键词对应参数名称。我们告诉Python解包一个字典,并通过使用两个星号“**”来把它当作函数的关键词参数。 下面的代码段与上面的代码段完全一样,现在我们使用字典参数,我们可以在运行时动态创建它。
>>> kwargs = {"username": "ains"}
>>> hello_user(**kwargs)
Hello ains!
好了,还记得上面的groupdict()方法?就是那个同样的在正则表达式完成匹配后返回{“username”: “ains”}的家伙?那么现在我们了解了kwargs,我们能很容易向我们的view_function传递字典匹配,完成NotFlask!
那么让我们把这些都塞进我们最终的类中。
class NotFlask():
def __init__(self):
self.routes = []
@staticmethod
def build_route_pattern(route):
route_regex = re.sub(r'()', r'(?P\1.+)', route)
return re.compile("^{}$".format(route_regex))
def route(self, route_str):
def decorator(f):
route_pattern = self.build_route_pattern(route_str)
self.routes.append((route_pattern, f))
return f
return decorator
def get_route_match(self, path):
for route_pattern, view_function in self.routes:
m = route_pattern.match(path)
if m:
return m.groupdict(), view_function
return None
def serve(self, path):
route_match = self.get_route_match(path)
if route_match:
kwargs, view_function = route_match
return view_function(**kwargs)
else:
raise ValueError('Route "{}"" has not been registered'.format(path))
接下来,就是见证奇迹的时刻,请看下面代码段:
app = NotFlask()
@app.route("/hello/")
def hello_user(username):
return "Hello {}!".format(username)
print app.serve("/hello/ains")
我们将得到输出:
Hello ains!