12.5 Web开发——装饰器与Flask路由¶
内容梗概¶
要看懂 Flask 示例代码,首先要解决 @app.route('/') 这个从没见过的语法。本课先系统讲解 Python 装饰器:它本质是一个"接收函数、返回函数"的函数,用闹钟只在工作日响的例子演示了从手写包装到 @ 语法糖的完整推导;然后回到 Flask,通过"转到定义"看 Flask 源码,讲清 @app.route('/') 的本质就是把 URL 路径与函数登记进**路由表**,并引出 Flask 对被路由函数的专业称呼 endpoint,最后动手给博客添加 /about、/posts 等多个路由。
知识点详解¶
装饰器(Decorator)(约 00:00–12:20)¶
- 问题引入:
@app.route('/')中@符号写在函数定义之前,从没见过——这叫**装饰器**。 - 定义:装饰器就是一个函数,它的返回值是另外一个函数,可以通过
@符号的语法来使用。 - 演示例子(新建
demo.py演示,注意别放进要交作业的 blog 文件夹):闹钟函数alarm只在工作日(周一到周五)响。 - 笨办法:在函数内写判断条件;若有 alarm1–alarm10 十个函数都要这个条件,就得写十次。
- 偷懒思路:Python 中一切皆对象,函数也是对象,可以当参数传递。
- 手写包装函数
check_time_alarm(f):- 参数
f就是要被包装的函数; - 内部定义一个子函数:先用标准库
datetime获取当前时间(datetime.now()),再用.weekday()方法得到今天周几(0–4 为周一到周五); - 若
weekday() < 5(工作日)才调用f(),否则直接返回; - 外层函数
check_time_alarm返回内部定义的这个函数对象。
- 参数
- 用法一(不用语法糖):
myalarm = check_time_alarm(alarm),然后myalarm()——此时调用的实际是内部包装后的函数。 - 用法二(Python 风格、推荐):在
alarm定义前写@check_time_alarm,效果完全一致——每次调用alarm时它都会被传进check_time_alarm,实际执行的是内部逻辑。 - 定位:装饰器是 Python 的**语法糖**——不用装饰器也能正常工作,但用了写起来非常容易。想给函数加限制条件、做额外操作时,就可以在外面套一个函数。更深的用法需自行扩展。
Flask 路由(约 12:20–26:10)¶
- 回到 Flask,用 VS Code"转到定义"看 Flask 源码中
app.py的route函数:@app.route('/')这个装饰器**本质上是调用了类似add_url_rule的函数,把装饰器里的路径(如根目录/)和被装饰的函数对应起来**。 - 拆解最小 Flask 应用:
from flask import Flask:导入 Flask 类;app = Flask(__name__):实例化一个 Flask 应用对象(参数默认传当前模块名,传别的也行);这个 app 对象内部就包含了前面讲的 Werkzeug 提供的 Web Server 模块和 WSGI 模块。- 路由表(URL 路由):WSGI 把路径和参数传给 App 后,App 需要一张表来查"根目录对应 index 函数、
/about对应 about 函数、/posts对应 posts 函数"。这张表叫**路由表**,是所有现代 Web 框架都有的概念;而这张表正是通过@app.route(...)装饰器一条条登记出来的。 - URL 结构复习:域名后面(含斜杠)的部分叫**路径**;浏览器输入
.../posts回车,经过几道转发到达程序,程序查路由表执行posts函数,返回一个字符串直接显示(这里还没有返回 HTML)。 - endpoint:Flask 对被路由的函数的专业称呼。源码里可见路径(path)与 endpoint 的对应关系,中间还有一个字符串是 endpoint 的 name(可以随便起,也可以与函数同名)。注意数据类型区别:name 是字符串,endpoint 本身是函数对象。
- 多个路由可以同时生效:用浏览器同时打开
/、/about、/posts三个页面即可(只是人一般一次只看一个页面,所以是一一对应使用)。
示例与演示¶
- demo.py 装饰器实验:
alarm+check_time_alarm,分别用"手动赋值myalarm"和"@语法"两种方式运行,加打印语句证明两种调用方式执行路径一致(都会先打印"今天是周几"再决定是否响铃)。 - Flask 路由实验:在 blog 项目的
app.py中依次添加: @app.route('/')→index(hello world)@app.route('/about')→about@app.route('/posts')→posts浏览器访问对应路径验证各自函数被执行;删掉路由后访问显示 404 Not Found(debug 模式自动重启,刷新即生效)。- 呼应作业要求:博客需要首页、关于我、文章列表等几个页面——就是靠多个路由设计出来的。
重点与难点¶
- 装饰器的本质一句话:接收函数、返回函数的函数;
@xxx只是把"手动把函数传进去、把返回的函数存回来"简化成了一行。 weekday()返回值:0 是周一,4 是周五,5 周六,6 周日;判断工作日用< 5(老师课上口误纠正过)。@app.route(路径)做的事就是**注册路由**:把路径和函数登记进路由表,别无魔法。- endpoint 是函数对象,endpoint name 是字符串,两者不要混为一谈。
- 交作业的 blog 文件夹里不要混入 demo.py 这类练习文件,应写个 README 放进仓库。
关联内容¶
- 装饰器依赖的前置知识:Python 中"一切皆对象"、函数内可以定义函数(第 11 章《函数进阶与类》11.1 函数进阶、11.2 作用域)。
datetime标准库的使用是顺带介绍,可自行查阅文档。- 路由表概念回扣 12.2 的 WSGI 模型(参数和路径传入应用)和 12.3 动态示例(
/data路径对应函数)。 - 本课的三条路由(首页/about/posts)在 12.7 被配上 Jinja2 模板,成为完整博客。