2009-10-13 41 views
8

Tôi đang cố gắng viết một mẫu cây rất đơn giản, đi bộ trong jinja2, sử dụng một số đối tượng tùy chỉnh với các phương thức đặc biệt quá tải (getattr, getitem, v.v.) Có vẻ đơn giản, và đi bộ python tương đương của cây hoạt động tốt, nhưng có một cái gì đó về cách mà sự đệ quy của Jinja làm việc mà tôi không hiểu. Mã được hiển thị bên dưới:Thẻ "đệ quy" của Jinja2 thực sự hoạt động như thế nào?

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) 

Mẫu đang tăng ngoại lệ như thể đệ quy không thực sự xảy ra. Các cuộc gọi bên trong được thực hiện, nhưng bằng cách nào đó tham chiếu đến 'thể loại' vẫn đề cập đến phụ huynh. Điều gì mang lại ở đây? Phải có một cái gì đó rất cơ bản tôi đang thiếu về cách thức các mẫu đệ quy này có nghĩa vụ phải làm việc. (Hoặc một cái gì đó rất cơ bản ngớ ngẩn mà tôi đang làm mà tôi không thể thấy.

+1

Bạn nên đăng trên danh sách gửi thư của pocoo-libs. Armin (tác giả của Jinja) sẽ thấy bài đăng của bạn ở đó. http://groups.google.com/group/pocoo-libs/topics –

Trả lời

7

Như tôi thấy từ mã của bạn, bạn hiểu đệ quy một cách chính xác, ngoại trừ một điều: nó thay thế lặp lại trong câu lệnh for, nhưng doesn ' t cập nhật biến (category trong mã của bạn) ban đầu được sử dụng trong đó. Vì vậy, bạn lồng nhau lặp vòng lặp thông qua trẻ em, nhưng set tra cứu thẻ trong gốc category, không phải là một truyền cho loop().

tôi đề nghị thay đổi __iter__() phương pháp để trở self.items.iteritems() và mẫu tới:

<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> 
Các vấn đề liên quan