bigywater.tech
Flask · 60

Jinja2 宏

宏怎么定义、怎么传内容、怎么接收可变参数?能不能读调用处的变量?在大循环里用宏会不会慢?这篇把宏的每个规则都跑一遍,再测它的代价。

3.3×
用宏(1500 次调用)渲染 500 行表格相对直接写的耗时倍数
varargs / kwargs
宏体里接收多余参数的两个自动变量
with context
让 import 进来的宏读到调用方变量的写法

定义与调用

实测 · 本机执行输出
  宏定义(forms.html 节选): {% macro input(name, value="", type="text", cls="input") -%}<input type="{{ type }}" name="{{ name }}" value="{{ value }}" class="{{ cls }}">{%- endmacro %}
  use.html       → <input type="text" name="user" value="" class="input">|<input type="password" name="pw" value="" class="big">
  use_from.html  → <input type="text" name="a" value="&lt;x&gt;" class="input">|<div class="card"><h3>标题</h3>正文2</div>
  inline.html    → 你好,世界|你好,ann|你好,bob

上一篇:Markup 与 safe;下一篇:模板中的惰性对象。宏与全局的可见性差别见自定义 Template Global。

call 与 caller

实测 · 本机执行输出
  caller_args.html → <tr><td>1:10</td></tr><tr><td>2:20</td></tr>
  card 宏里用 caller() 包裹正文(见 use_from.html 输出)

可变参数与递归

实测 · 本机执行输出
  在签名里写 *args → TemplateSyntaxError: expected token 'name', got '*'
  list_all(1, 2, k=3) → args=[1, 2]|kwargs={&#39;k&#39;: 3}
  fact(5) → 120
  with_defaults(1) → a=1,b=2,c=1 (默认值表达式可以引用前面的参数)
  宏的属性 name / arguments / defaults / catch_kwargs / catch_varargs / caller: m|(&#39;a&#39;, &#39;b&#39;)||True|True|False

作用域

实测 · 本机执行输出
  同一个模板里定义的宏读外层的 {% set x %}: 外层
  import 默认 vs with context: [看不到 outer_var]|[外层变量]

自动转义

实测 · 本机执行输出
   <b>&lt;i&gt;</b>|<B>&LT;I&GT;</B>|16
  不加括号 {{ m }} 输出的是宏对象: &lt;Macro &#39;m&#39;&gt;

开销

实测 · 本机执行输出
  直接写                            0.986 ms/次
  同模板里的宏(1500 次调用)               3.236 ms/次
  import 进来的宏(1500 次调用)          3.234 ms/次
  每行 include 一个模板(500 次)         2.083 ms/次
  相对直接写: {'直接写': '1.00×', '同模板里的宏(1500 次调用)': '3.28×', 'import 进来的宏(1500 次调用)': '3.28×', '每行 include 一个模板(500 次)': '2.11×'}

分步演示

宏
本步的对象

    本文用到的工具与边界

    • 本机 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,数字每次运行会有小幅抖动
    • 没有验证:宏在异步模板里的行为、宏的 caller 嵌套多层时的变量解析、{% macro %} 与 {% call %} 的沙箱限制、把宏编译进 Python 模块(ModuleLoader)的效果
    京ICP备2026067502号-1京公网安备11010502063487号