python - Jinja2 "recursive"标签实际上是如何工作的?

标签 python recursion templates jinja2

我正在尝试在 jinja2 中编写一个非常简单的树遍历模板,使用一些具有重载特殊方法(getattr、getitem 等)的自定义对象这看起来很简单,树的等效 python 遍历工作正常,但是 Jinja 的递归工作方式有些我不明白。代码如下所示:

from jinja2 import Template

class Category(object):

    def __init__(self, name):
        self.name = name
        self.items = {}
        self.children = True

    def __iter__(self):
        return iter(self.items)

    def add(self, key, item):
        self.items[key] = item
        return item

    def __getitem__(self, item):
        return self.items[item]

    def __getattr__(self, attr):
        try:
            return self.items[attr]
        except KeyError:
            raise AttributeError(attr)

    def __str__(self):
        return "<Category '%s'>" % self.name

template = '''
<saved_data>
{% for key in category recursive %}
    {% set item = category[key] %}
    {% if item.children %}
        <category name="{{key}}">
            {{ loop(item) }}
        </category>
    {% else %}
        <item name="{{ key }}" value="{{ item }}" />
    {% endif %}
{% endfor %}
</saved_data>
'''

b = Category('root')
c = b.add("numbers", Category('numbers'))
c.add("one", 1)
c.add("two", 2)
c.add("three", 3)
d = b.add("letters", Category('letters'))
d.add('ay','a')
d.add('bee','b')
d.add('cee','c')
e = d.add("bools", Category('bools'))
e.add('tru', True)
e.add('fals', False)

def walk(c, depth=0):
    for key in c:
        item = c[key]
        print (' '*depth) + str(item)
        if hasattr(item, 'children'):
            walk(item, depth+3)
print "Python walking the tree:"
walk(b)

print ""
print "Jinja2 Walking the tree:"
t = Template(template)
print t.render(category = b)

模板引发异常,就好像递归实际上没有发生一样。进行了内部调用,但不知何故,对“类别”的引用仍然指代父级。这里有什么?关于这些递归模板应该如何工作,我肯定缺少一些非常基本的东西。 (或者我正在做的一些我根本看不到的非常愚蠢的事情。

最佳答案

正如我从您的代码中看到的,您正确理解递归,除了一件事:它确实替换了 for 语句中的 iterable,但不更新最初在其中使用的变量(代码中的 category) .因此,您嵌套循环遍历子项,但 set 标签在原始 category 中查找,而不是传递给 loop()

我建议更改 __iter__() 方法以返回 self.items.iteritems() 和模板:

<saved_data>
{% for key, item in category recursive %}
        {% if item.children %}
                <category name="{{key}}">
                        {{ loop(item) }}
                </category>
        {% else %}
                <item name="{{ key }}" value="{{ item }}" />
        {% endif %}
{% endfor %}
</saved_data>

关于python - Jinja2 "recursive"标签实际上是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1563276/

相关文章:

python - 如何在 Python 中使用 BeautifulSoup 分离标签?

python - Pygame 混合器不循环

python - 如何消除数独方 block 中的凸性缺陷?

python - Pygame粒子效果

database - Oracle - 执行递归 'WITH' 查询时检测到循环

Java递归地计算给定字符串中的x

c++ - 这个 "<>"在模板类函数中意味着什么?

c++ - 为什么 C++ 不能更轻松地对类型进行编译时查询?

python - 向文件描述符写入 0 个字符

c++ - 在 gcc 上编译代码,但不在 msvc 上编译