Повторно использованная переменная в шаблоне Mako вызывает "UnboundLocalError: локальная переменная 'xyz', на которую ссылаются до назначения" - PullRequest
1 голос
/ 14 февраля 2012

У меня есть эта "забавная" проблема.Я знаю, что это сообщение об ошибке встречается во многих местах, но я не смог найти одно явно связанное с Мако.

В шаблоне Мако у меня есть (фрагмент):

<%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.Если бы у меня была та же ошибка с переменной в <%def>, может быть ясно, что нельзя повторно использовать одно и то же имя переменной, но в этом случае я весьма озадачен, что такое происходит.

Может кто-нибудь сказатьКак мне избежать этого, кроме переименования переменной label в цикле for?Если я переименую переменную цикла for, проблема исчезнет.Я перехожу из другой системы шаблонов, в которой не было ошибок такого рода, поэтому подобный сценарий случается довольно часто.

Спасибо за любые указатели,

D.

РЕДАКТИРОВАТЬ для ясности:

Я звоню по своему шаблону, используя:

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

Мой вопрос : Почему тот факт, что у меня есть % for (label, field_name) -loop, переменная 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>

Я не получаю ошибки, даже если ${label} используется в моем <%def>.

Кроме того, чтобы добавить информацию для использования шаблона, я добавил <%inherit>, и вот как other.makoопределен (фрагмент):

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

Так что мне не нужно передавать какое-либо значение в my_method().

Надеюсь, это прояснит вопрос.

Ответы [ 2 ]

2 голосов
/ 21 февраля 2012

Лучше всего думать, что шаблон 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.

0 голосов
/ 14 февраля 2012

Я думаю, вам нужно включить метку в аргументы 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, которые я не совсем понимаю, но это, кажется, самый безопасный вариант. По моему мнению, повторное использование имен переменных, таких как это, в любом случае является плохой формой и ведет к непредвиденному поведению, подвержено ошибкам и т. Д.

Из моей оценки видно, что это может быть особенностью мако в том, как он обрабатывает пространства имен. Рассмотрим следующие примеры. Первый вызывает то же исключение 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

Чтобы продемонстрировать, что Мако оценивает шаблон не так, как вы могли бы ожидать, вот пример аналогично структурированного чистого 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
...