在我上一篇文章,我搭了一个框架,模拟了Flask网站上“@app.route(‘/')”第一条例子的行为。

如果你错过了那篇“这不是魔法”,请点击这里。

在这篇文章中,我们打算稍微调高点难度,为我们的URL加入可变参数的能力,在本文的最后,我们将支持下述代码段所期望达到的行为。

app = Flask(__name__)

@app.route("/hello/")

def hello_user(username):

return "Hello {}!".format(username)

这样下面的路径实例(path):

/hello/ains

将会匹配上面的路径,给我们的输出为

Hello ains!

以正则的形式表达我们的路径。

现在我们将允许我们的URL动态变化,我们不再能够将用先前使用“@app.route()”注册的路径直接与路径实例比较。

我们将用什么替代?我们需要用上正则表达式,这样我们就可以将路径作为一种模式进行匹配,而不和一条固定的字符串比较了。

我不打算在本文展开讨论正则表达式的细节,不过如果你需要一份复习资料,可以点击这个网站。

那么,我们的第一步是将我们的路径转化成正则表达式模式,这样我们就能在输入路径实例时进行匹配。我们也将使用这个正则表达式提取我们感兴趣的变量。

那么,匹配路径”/hello/”的正则表达式该长啥样呢?

嗯一个简单的正则表达式譬如“^/hello/(.+)$”将是个好的开始,让我们一起看看它和代码是怎么一起工作的:

import re

route_regex = re.compile(r"^/hello/(.+)$")

match = route_regex.match("/hello/ains")

print match.groups()

将会输出:

('ains',)

不错,不过,理想情况是我们想要维护我们已经匹配上的第一组链接,并且从路径“/hello/”识别出“username”。

命名捕获组

幸运的是,正则表达式也支持命名捕获组,允许我们给匹配组分配一个名字,我们能在读取我们的匹配之后找回它。

我们可以使用下述符号,给出第一个例子识别“username”的捕获组。

/hello/(<?P .+)"

然后我们可以对我们的正则表达式使用groupdict()方法,将所有捕获组当作一个字典,组的名字对应匹配上的值。

那么我们给出下述代码:

route_regex = re.compile(r'^/hello/(?P.+)$')

match = route_regex.match("/hello/ains")

print match.groupdict()

将为我们输出以下字典:

{'username': 'ains'}

现在,有了我们所需要的正则表达式的格式,以及如何使用它们去匹配输入的URLs的知识,最后剩下的是写一个方法,将我们声明的路径转换成它们等价的正则表达式模式。

要做这个我们将使用另一个正则表达式(接下来将全是正则表达式),为了让我们路径中的变量转换成正则表示式模式,那这里作为示范我们将将“”转换成“(?P.+)”。

听起来太简单了!我们将可以只用一行新代码实现它。

def build_route_pattern(route):

route_regex = re.sub(r'()', r'(?P1.+)', route)

return re.compile("^{}$".format(route_regex))

print build_route_pattern('/hello/')

这里我们用一个正则表达式代表所有出现的模式(一个包含在尖括号中的字符串),与它的正则表达式命名组等价。

re.sub的第一个参数 我们将我们的模式放进括号,目的是把它分配到第一个匹配组。在我们的第二个参数,我们可以使用第一匹配组的内容,方法是写1(2将是第二匹配组的内容,以此类推…….)

那么最后,输入模式

/hello/

将给我们正则表达式:

^/hello/(?P.+)$

推陈出新

让我们扫一眼上次我们写的简单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'(?P1.+)', 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'(?P1.+)', 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!

python函数库app_Python的Flask框架中@app.route的用法教程相关推荐

  1. python函数库分类及实例_Python中Scikit-Learn库的分类方法总览

    译者丨野生大熊猫 https://mp.weixin.qq.com/s/hmNKdM3pA3Mq9vq0TQXgOg 简介 你是一个正在进入机器学习领域的Python程序员吗? 掌握Scikit-Le ...

  2. python处理信号机制_Python的Flask框架中的signals信号机制

    Flask 提供了信号(Signals)功能,是一种消息分发机制.类似于钩子(Hooks).使用信号功能可以降低程序的耦合,分解复杂的业务模型.例如在更新了产品数据后,可以发送一个信号.当有需要对产品 ...

  3. python flask框架下登录注册界面_Python的Flask框架中实现简单的登录功能的教程

    Python 的 Flask 框架中实现简单的登录功能的教程 , 登录是各个 web 框架中的基础功能 , 需要的朋友可以参考下 回顾 在前面的系列章节中, 我们创建了一个数据库并且学着用用户和邮件来 ...

  4. 如何用python做后端写网页-flask框架

    如何用python做后端写网页-flask框架 什么是Flask 安装flask模块 Hello World 更深一步:数据绑定 后端传入数据 从前端获取数据 数据库连接 screen 创建后台 查看 ...

  5. Flask 框架中 上下文基础理念,包括cookie,session存储方法,requset属性,current_app模块和g模块...

    Flask中上下文,分为请求上下文和应用上下文.既状态留存 ,就是把变量存在某一个地方可以调用 请求上下文:实际就是request和session用法理念,既都是可以存储东西. 应用上下文:既变量共享 ...

  6. python指南针_如何用用Python 函数库 APIs 编写?指南针在这里

    原标题:如何用用Python 函数库 APIs 编写?指南针在这里 本篇文章基于 2017 PyCon 大会上的演讲:How to make a good library API.列出对于构建 Pyt ...

  7. flask框架中的Jinja2模板引擎

    简介 在flask框架中通常使用Jinja2模板引擎来实现复杂页面的渲染. 本章主要介绍Jinja2模板引擎的基本结构和使用方法. 如何使用flask框架渲染模板 在模板中传递一个或者多个参数 if语 ...

  8. 离线安装python第三方库的实用方法:解决公司内网,服务器/电脑不能上网却需要安装python三方库问题(上:Windows环境中)

    离线安装python第三方库的实用方法:解决公司内网,服务器/电脑不能上网却需要安装python三方库问题(上:Windows环境中) 参考文章: (1)离线安装python第三方库的实用方法:解决公 ...

  9. php中条件查询语句,thinkphp3.2框架中where条件查询用法总结

    本文实例讲述了thinkphp3.2框架中where条件查询用法.分享给大家供大家参考,具体如下: thinkphp3.2 where 条件查询 在连贯操作中条件where的操作有时候自己很晕,所以整 ...

最新文章

  1. RGBA和ARGB的区别
  2. 1个多月就能看到效果的减肥大法 - 生活至上,美容至尚!
  3. aapt.exe已停止工作 r.java_【转】android错误 aapt.exe已停止工作的解决方法
  4. CentOS 6.3下rsync服务器的安装与配置[转]
  5. Linux下安装 Indy 到 Lazarus
  6. ROS: Ubuntu16.04安装ROS-kinetic
  7. 一般试卷的纸张大小是多少_pdf试卷怎么打印在A3纸上
  8. 作业:Regular Expression
  9. 谈谈疑似中介规则策略
  10. 什么是数据中台,让企业的数据作为生产资料转变为数据生产力
  11. 【英语阅读】纽约时报 | 感染新冠病毒是怎样的感受
  12. 计算机小高考要点,小高考的复习计划
  13. 【服务器数据恢复】IBM服务器RAID控制器出错的数据恢复案例
  14. python基础编程小实例4——恺撒密码
  15. 对计算机专业学生的七个建议(作者:Joel Spolsky)
  16. JavaScript 数据类型和类型转换
  17. 广告主流量主怎么申请(微信)
  18. LEETCODE | PYTHON | 剑指 Offer 58 - Ⅱ | 左旋转字符串
  19. (原创)Linux设备轮询机制分析
  20. App通过QQ/微信登录绑定用户信息的一般流程

热门文章

  1. H.264官方软件JM源代码简单分析-编码器lencod
  2. 『HTMLCSS』文本标签
  3. FMCW雷达测距、测速与测角
  4. Android 中文URL转码
  5. java minhash_MinHash概述及举例
  6. M-Arch(番外14)GD32L233评测-驱动段码LCD
  7. 深度分析美光科技在人工智能领域“被忽视和低估”的投资机会
  8. Pandas获取SQL数据库read_sql()函数及参数一文详解+实例代码
  9. VCF文件与vcftools简单介绍
  10. 串口通讯粘包处理方法