我有这个“有趣”的问题。我知道很多地方都有这个错误信息,但我找不到与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()}
,我不会收到任何错误,${label}
中的<%def>
值就是那个我想要的,不是来自for-loop的那个。如果我对<%def>
中的变量有同样的错误,可能很清楚不重用相同的变量名,但在这种情况下,我很困惑这种事情发生了。
有谁可以告诉我除了在for-loop中重命名变量 label 之外我怎么能避免这种情况?如果我重命名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()}
中的错误,其中as它没有给我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>
即使我的${label}
使用了<%def>
,我也没有收到任何错误。
另外,要添加模板使用情况的信息,我添加了<%inherit>
,以下是other.mako
的定义方式(摘要):
<%def name="my_method()">Default value</%def>
Value of my_method() = ${self.my_method()}
所以我不需要将任何值传递给my_method()
。
希望这会使问题更加明确。
答案 0 :(得分:2)
最好将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模板中工作。
答案 1 :(得分:0)
我认为你需要在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))
输出:
Traceback (most recent call last): ... File "C:\Python26\ArcGIS10.0\Lib\site-packages\mako-0.6.2-py2.6.egg\mako\runtime.py", line 704, in _exec_template callable_(context, *args, **kwargs) File "memory:0xb5b6b0", line 22, in render_body UnboundLocalError: local variable 'label' referenced before assignment
示例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))
输出:
Text in "label": eggs Elements of "some_list": [('foo', 'bar'), ('spam', 'eggs')] Labels and names in "some_list" label: name -> foo: bar label: name -> spam: eggs Eggs
为了证明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)
输出:
Text in "label": bogus Elements of "some_list": [('foo', 'bar'), ('spam', 'eggs')] Labels and names in "some_list" label: name -> foo:bar label: name -> spam:eggs Caps "label": Spam