bigywater.tech
Flask · 14

Flask 与 Werkzeug 的关系

常说 Flask 是「Werkzeug + Jinja2」,具体是哪些类、哪些功能来自它们?只用 Werkzeug 能做到什么?Flask 又多加了什么?这篇用继承链、依赖列表和一个纯 Werkzeug 应用来回答。

6
Flask 3.1.3 的必装依赖个数(不含 Python 版本相关的条目)
18.2 µs
Flask 相对纯 Werkzeug 每个请求多出的耗时(test client)
12 行
纯 Werkzeug 应用的代码量(见第三节源码)

依赖

实测 · 本机执行输出
  Requires-Dist(不含可选的 extra):
    blinker>=1.9.0
    click>=8.1.3
    importlib-metadata>=3.6.0; python_version < '3.10'
    itsdangerous>=2.2.0
    jinja2>=3.1.2
    markupsafe>=2.1.1
    werkzeug>=3.1.0
  本机实际安装的版本: {'flask': '3.1.3', 'werkzeug': '3.1.9', 'jinja2': '3.1.6', 'itsdangerous': '2.2.0', 'click': '8.5.0', 'markupsafe': '3.0.3', 'blinker': '1.9.0'}

上一篇:WSGI Callable 的真实结构;下一篇:Flask Debug Mode 与自动重载。

继承关系

实测 · 本机执行输出
  Flask.request_class    flask.wrappers.Request → werkzeug.wrappers.request.Request → werkzeug.sansio.request.Request
  Flask.response_class   flask.wrappers.Response → werkzeug.wrappers.response.Response → werkzeug.sansio.response.Response
  Flask.url_map_class    werkzeug.routing.map.Map
  Flask.url_rule_class   werkzeug.routing.rules.Rule → werkzeug.routing.rules.RuleFactory
  应用上的对象来自: {'app.url_map': 'werkzeug.routing.map.Map', 'app.jinja_env': 'flask.templating.Environment', 'app.config': 'flask.config.Config', 'app.session_interface': 'flask.sessions.SecureCookieSessionInterface', 'app.json': 'flask.json.provider.DefaultJSONProvider', 'app.aborter': 'werkzeug.exceptions.Aborter'}

纯 Werkzeug 应用

实测 · 本机执行输出
  纯 Werkzeug 应用:
      1 | from werkzeug.wrappers import Request, Response
      2 | from werkzeug.routing import Map, Rule
      3 | from werkzeug.exceptions import HTTPException
      4 | url_map = Map([Rule("/hello/<name>", endpoint="hello"), Rule("/", endpoint="index")])
      5 | @Request.application
      6 | def application(request):
      7 |     adapter = url_map.bind_to_environ(request.environ)
      8 |     try:
      9 |         endpoint, args = adapter.match()
     10 |         return Response(f"{endpoint}: {args or ''} q={request.args.get('q')}")
     11 |     except HTTPException as e:
     12 |         return e
  GET /                → 200 OK | index:  q=None
  GET /hello/ann?q=1   → 200 OK | hello: {'name': 'ann'} q=1
  GET /nope            → 404 NOT FOUND | <!doctype html>
<html lang=en>
<title>404 Not Found</title>

Flask 多出的成本

实测 · 本机执行输出
  纯 Werkzeug 55.1 µs/请求;Flask 73.3 µs/请求;Flask 多出 18.2 µs(约 1.33 倍)——多出来的是上下文推入弹出、会话、钩子、响应转换等
  Flask 里有、纯 Werkzeug 里没有的功能(从属性存在性验证):
    app.config / 钩子 / 蓝图 / 模板渲染 / session:Flask 对象有 True;纯 Werkzeug 函数有 False

分步演示

Flask 与 Werkzeug
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动
    • 没有验证:Jinja2、itsdangerous、click、blinker 各自在 Flask 中承担的全部功能(本篇只验证了依赖列表与部分对象的类型)、多出的耗时具体由哪些步骤构成(没有逐项拆分)、真实网络下的差别
    京ICP备2026067502号-1京公网安备11010502063487号