跳转至

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 模板,成为完整博客。