Я нашел ответ на этот вопрос в Github: https://github.com/pallets/jinja/issues/148#issuecomment-10267923
Важной частью для меня является то, что шаблон визуализируется путем генерации промежуточного кода Python, а затем оценки этого кода. В конце код, используемый для создания шаблона, выглядит примерно так:
u'\n%s\n%s\n%s\n%s\n' % (
l_my_list,
context.call(l_add_list, l_my_list),
context.call(l_add_list, l_my_list),
context.call(l_add_list, l_my_list),
)
Это можно смоделировать с помощью следующего кода:
def a( l ):
l.append( 4 )
return l
l = list()
print '%s %s %s' % ( a( l ), a( l ), a( l ) )
# Output: [4, 4, 4] [4, 4, 4] [4, 4, 4]
По сути, каждая функция возвращает ссылку на один и тот же список, а не новую копию списка. Таким образом, результаты не такие, как вы могли ожидать. Это была старая проблема, которая не вызывала особого интереса, поэтому я не думаю, что есть какие-либо планы изменить ее работу.