Domanda

Sto cercando di scrivere un molto semplice, modello di albero-walking in Jinja2, utilizzando alcuni oggetti personalizzati con metodi speciali sovraccarica (getattr, GetItem, ecc) Sembra semplice, e il pitone passeggiata equivalente dell'albero funziona bene, ma c'è qualcosa nel modo in cui la ricorsione di Jinja opere che non capisco. Il codice è il seguente:

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)

Il modello sta sollevando un'eccezione, come se la ricorsione non ha effettivamente avuto luogo. La chiamata interno è realizzato, ma in qualche modo il riferimento alla 'categoria' si riferisce ancora al genitore. Ciò che dà qui? Ci deve essere qualcosa di molto fondamentale che mi manca su come questi modelli ricorsivi si suppone di lavorare. (O qualcosa di molto fondamentalmente stupido che sto facendo che non riesco proprio a vedere.

È stato utile?

Soluzione

Per come la vedo dal codice si capisce ricorsivo correttamente, tranne una cosa: non sostituire iterabile nel for, ma non aggiorna variabili (category nel codice) originariamente utilizzato in essa. Così, si nidificato itera un ciclo tra i bambini, ma le ricerche di tag set in category originale, non si passava al loop().

Suggerisco di cambiare metodo __iter__() per tornare self.items.iteritems() e template a:

<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>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top