Mako 模板中重复使用的变量导致"UnboundLocalError: local variable 'xyz' referenced before assignment"



我遇到了这个"有趣"的问题。我知道这个错误消息在很多地方都可以找到,但我找不到一个与Mako明确相关的消息。

在Mako模板中,我有(片段):

<%inherit file="other.mako"/>
<%def name="my_method()">Search for ${label}</%def>
[...]
<h2>${label.capitalize()} found: ${len(l)}</h2>
...
<ol>
% for (label, field_name) in some_list:
    <li>${label}: ${field_name}</li>
% endfor
</ol>

我会得到错误:

UnboundLocalError: local variable 'label' referenced before assignment

奇怪的是,如果我不使用第二个${label.capitalize()},我就不会得到任何错误,而<%def>${label}的值是我想要的,而不是for循环中的值。如果我在<%def>中的变量也有同样的错误,那么不重用相同的变量名可能是显而易见的,但在这种情况下,我对发生这样的事情感到非常困惑。

除了在for循环中重命名变量标签之外,有人能告诉我如何避免这种情况吗?如果我重命名for循环变量名,问题就会消失。我正在从另一个没有这种错误的模板系统转移,所以这种类似的情况经常发生。

感谢您的指点,

D。

编辑以提高清晰度:

我正在使用调用我的模板

renderers.render_to_response(my_mako_tmpl,
         {'label': 'value', 'somelist':[a,b,c], 'l':[]},
         request=request)

我的问题是:为什么我有% for (label, field_name)-循环,变量label给了我一个${label.capitalize()}中的错误,因为它没有给我任何Search for ${label}的错误。

如果我将for循环更改为:

% for (label_name, field_name) in some_list:

我没有错。

如果我不改变for循环,但我改变了:

<h2>${label.capitalize()} found: ${len(l)}</h2>

<h2>Items found: ${len(l)}</h2>

即使在我的<%def>中使用了${label},我也不会出错。

此外,为了添加模板使用的信息,我添加了<%inherit>,下面是如何定义other.mako的(片段):

<%def name="my_method()">Default value</%def>
Value of my_method() = ${self.my_method()}

所以我不需要向my_method()传递任何值。

希望这能让问题更清楚。

最好将Mako模板视为类似于一段python代码。因此,与python一样,如果希望变量同时具有本地作用域和全局作用域(或嵌套作用域),则会出现问题。

将模板视为一个接受变量的函数,并在其中定义各种其他函数,包括body()函数,那么您的问题实际上类似于以下

>>> def f(x):
...     def body():
...         print x
...         for x in range(5):
...             print x
...     body()
... 
>>> f(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in f
  File "<stdin>", line 3, in body
UnboundLocalError: local variable 'x' referenced before assignment

您不应该期望它在Python中工作,同样,您也不应该期望其在Mako模板中工作。

我认为您需要在my_method参数中包含标签。

<%def name="my_method(label)">Search for ${label}</%def>
[...]
<h2>${label.capitalize()} found: ${len(l)}</h2>
...
<ol>
% for (label, field_name) in some_list:
    <li>${label}: ${field_name}</li>
% endfor
</ol>

跟踪

据我所知,您将不得不更改循环变量名称。我可能不完全理解Mako或Python名称空间的细微差别,但这似乎是最安全的选择。在我看来,重复使用这样的变量名无论如何都是不好的形式,会导致意外行为,容易出错,等等。

根据我的评估,这可能是mako处理名称空间的一个特点。请考虑以下示例。第一个引发相同的UnboundLocalError异常。第二个在结构上相同,不引发异常。

示例1引发UnboundLocalError:

from mako.template import Template
src = """
Text in "label": ${label}
Elements of "some_list": ${some_list}
Labels and names in "some_list"
% for (label,name) in some_list:
    label: name -> ${label}: ${name}
% endfor
${label.capitalize()}
"""
my_template = Template(src)
s = [('foo', 'bar'), ('spam', 'eggs')]
data = {'label': 'bogus', 'some_list':s, 'l':[1, 2, 3, 4]}
print(my_template.render(**data))

输出:

追踪(最近一次通话):。。。文件"C:\Python26\ArcGIS10.0\Lib\site-packages\mako-0.6.2-py2.6.egg\mako\runtime.py",第704行,在_exec_template中可调用_(上下文,*args,**kwargs)文件"内存:0xb5b6b0",第22行,在render_body中UnboundLocalError:在赋值之前引用了局部变量"label"

示例2成功评估:

from mako.template import Template
src = """
Text in "label": ${label}
Elements of "some_list": ${some_list}
Labels and names in "some_list"
% for (loop_label,name) in some_list:
    label: name -> ${loop_label}: ${name}
% endfor
${label.capitalize()}
"""
my_template = Template(src)
s = [('foo', 'bar'), ('spam', 'eggs')]
data = {'label': 'bogus', 'some_list':s, 'l':[1, 2, 3, 4]}
print(my_template.render(**data))

输出:

"标签"中的文字:鸡蛋"some_list"的元素:[('fo','bar'),('spam','eggs')]"some_list"中的标签和名称label:name->foo:bar标签:名称->垃圾邮件:鸡蛋鸡蛋

为了证明Mako并没有像您预期的那样评估模板,这里有一个结构相似的纯Python示例,它的评估结果很好。

src = """
print('Text in "label": %s' % label)
print('Elements of "some_list": %s' % some_list)
print('')
print('Labels and names in "some_list"')
for (label,name) in some_list:
    print('    label: name -> %s:%s' % (label, name))
print('')
print('Caps "label": %s' % label.capitalize())
"""
code = compile(src, 'None', 'exec')
s = [('foo', 'bar'), ('spam', 'eggs')]
data = {'label': 'bogus', 'some_list':s, 'l':[1, 2, 3, 4]}
eval(code, {}, data)

输出:

"标签"中的文本:伪造"some_list"的元素:[('fo','bar'),('spam','eggs')]"some_list"中的标签和名称label:name->foo:bar标签:名称->垃圾邮件:鸡蛋大写"label":垃圾邮件

相关内容

  • 没有找到相关文章

最新更新