Jinja2模板中set修改变量为何无法在循环后续持久生效?
Jinja2循环内变量重置问题分析与解决
问题根源
你遇到的问题是Jinja2的作用域规则导致的:
- 循环外定义的
has_swimming = 0属于全局作用域变量 - 在循环内执行
{% set has_swimming = 1 %}时,Jinja2会创建一个当前循环迭代的局部变量,这个变量只在本次迭代生效,下一次循环时局部变量被销毁,程序会重新引用全局的has_swimming=0,所以每次循环都相当于把变量重置回初始值,这才导致第二个SWIMMING条目又触发了find swim。
解决方法
因为你已经启用了jinja2.ext.do扩展,这里提供两种简单可行的方案:
方案1:用Namespace对象存储状态(推荐)
Jinja2的namespace是可变对象,其属性可以在循环内修改并保留状态,写法更直观:
修改模板部分代码如下:
{% set ns = namespace(has_swimming=0) %} {% for row in Class['Students'] %} {% set name = row['name'] -%} {% set hobby = row['hobby'] %} {% if hobby == 'SWIMMING' and ns.has_swimming == 0 %} {% set ns.has_swimming = 1 %} find swim============= {% endif %} name is {{name}}, hobby is {{hobby}} {% if hobby != 'SWIMMING' and ns.has_swimming == 1 %} {% set ns.has_swimming = 0 %} end=============== {% endif %} {% endfor %} {% if ns.has_swimming == 1%} end=============== {% endif %}
方案2:用可变列表存储状态
利用列表是可变类型的特性,修改列表元素来保留状态:
{% set has_swimming = [0] %} {% for row in Class['Students'] %} {% set name = row['name'] -%} {% set hobby = row['hobby'] %} {% if hobby == 'SWIMMING' and has_swimming[0] == 0 %} {% do has_swimming.__setitem__(0, 1) %} find swim============= {% endif %} name is {{name}}, hobby is {{hobby}} {% if hobby != 'SWIMMING' and has_swimming[0] == 1 %} {% do has_swimming.__setitem__(0, 0) %} end=============== {% endif %} {% endfor %} {% if has_swimming[0] == 1%} end=============== {% endif %}
验证结果
修改后运行代码,将得到你预期的输出:
name is CHOI, hobby is RUNNINg name is KIM, hobby is RUNNINg find swim============= name is JEON, hobby is SWIMMING name is YOON, hobby is SWIMMING end===============
内容的提问来源于stack exchange,提问作者seonguk.jeon
相关产品推荐
相关产品推荐

