在 jinja2 中创建和填充字典
Creating and populating a dictionary in jinja2
import jinja2
from jinja2 import Template
records = [{'a':1,'b':1, 'c':1},{'a':1,'b':1, 'c':1}, {'a':2,'b':1, 'c':1}, {'a':3,'b':1, 'c':1}]
t = jinja2.Template("""
{% set record_info = dict() %}
{% for item in records %}
{% set key = str(item['a'])+str(item['b'])+str(item['c']) %}
{% if key in record_info %}
{% set record_info.key += 1 %}
{% else %}
{% set record_info.key = 1 %}
{% endif %}
{% endfor %}
{{record_info}}""")
这给了我:
Traceback (most recent call last):
File "<stdin>", line 11, in <module>
File "/Library/Python/2.7/site-packages/jinja2/environment.py", line 945, in __new__
return env.from_string(source, template_class=cls)
File "/Library/Python/2.7/site-packages/jinja2/environment.py", line 880, in from_string
return cls.from_code(self, self.compile(source), globals, None)
File "/Library/Python/2.7/site-packages/jinja2/environment.py", line 591, in compile
self.handle_exception(exc_info, source_hint=source_hint)
File "/Library/Python/2.7/site-packages/jinja2/environment.py", line 780, in handle_exception
reraise(exc_type, exc_value, tb)
File "<unknown>", line 6, in template
jinja2.exceptions.TemplateSyntaxError: expected token 'end of statement block', got '.'
我做错了什么?
我可以这样做,有什么改进吗?
records = [{'a':1,'b':1, 'c':1},{'a':1,'b':1, 'c':1}, {'a':2,'b':1, 'c':1}, {'a':3,'b':1, 'c':1}]
t = jinja2.Template("""
{% set record_info = dict() %}
{% for item in records %}
{% set key = item['a'] ~ ':' ~ item['b'] ~ ':' ~ item['c'] %}
{% if key in record_info %}
{% set _dummy = record_info.update( {key: record_info[key]+1 }) %}
{% else %}
{% set _dummy = record_info.update({ key:1 }) %}
{% endif %}
{% endfor %}
{{record_info}}""")
print t.render(records=records)
{u'1:1:1': 2, u'3:1:1': 1, u'2:1:1': 1}
您可以使用 "set".
{% set x = my_dict.__setitem__("key", "value") %}
然后您可以使用 my_dict,它将具有更新后的值(不要介意 x,它就在那里,不会引发错误)。这已经在另一个答案中,在 here.
中
快速解决方案
现有的答案工作得很好,但既然你要求任何改进,我会尝试。
from jinja2 import Template
records = [{'a':1,'b':1, 'c':1},{'a':1,'b':1, 'c':1}, {'a':2,'b':1, 'c':1}, {'a':3,'b':1, 'c':1}]
t = Template("""
{%- set record_info = dict() %}
{%- for item in records %}
{%- set key = item['a'] ~ ':' ~ item['b'] ~ ':' ~ item['c'] %}
{%- do record_info.update({key: 1 if not record_info[key] else record_info[key]+1}) %}
{%- endfor -%}
{{record_info}}""",
extensions=['jinja2.ext.do']
)
print(t.render(records=records))
改进
- 显示导入 - 一些来到这里的 SO 用户可能是 Python 的新手,需要完整的上下文
- 使用 Python3 和
print()
函数(不是批评 - 我意识到这是在 2017 年,尽管 from __future__
也可以)
- 允许使用 do“表达式语句”扩展
- 使用
do
而不是设置 _dummy
变量
- 避免使用
{%-
和 -%}
的所有额外渲染 newlines/whitespace 将 -
添加到那些 begin/end 标签中
其他变化
这些是否是改进是主观的——可读性是提高了还是受到了阻碍?
- 使用内联 if(三元)启用删除
else
子句
备注
使用默认值
这一行:
{%- do record_info.update({key: 1 if not record_info[key] else record_info[key]+1}) %}
也可以写成default
:
{%- do record_info.update({key: (record_info[key] | default(0)) + 1 }) %}
请注意,对现有 record_info[key]
的检查会通过管道传输到默认值,即使当密钥尚不存在时这是一个错误。
例如,这不起作用:
{%- do record_info.update({key: (record_info[key]+1 | default(1)) }) %}
...因为当它尝试计算 record_info[key]+1
时 record_info[key]
错误未被处理。
环境和装载机
文档建议使用 Loader
例如PackageLoader
启用模板继承等。在您的示例中,它看起来像是一个快速设置,因此我将忽略该要求。请注意,无论如何都要使用 Template constructor directly will create a shared 环境,而没有 Loader 或继承的好处。
如果您使用 PackageLoader
,您将有一个包名称和一个名为 templates
的文件夹用于加载它们。将模板放在单独的文件中也很好。
为了快速使用真正的加载器而无需那些单独的文件,FunctionLoader
很有用。您可以向函数添加更多模板字符串,并按名称 return 它们,例如
from jinja2 import Environment, FunctionLoader
records = [{'a':1,'b':1, 'c':1},{'a':1,'b':1, 'c':1}, {'a':2,'b':1, 'c':1}, {'a':3,'b':1, 'c':1}]
def my_template(name: str) -> str:
if name == 'first_one':
return """
{%- set record_info = dict() %}
{%- for item in records %}
{%- set key = item['a'] ~ ':' ~ item['b'] ~ ':' ~ item['c'] %}
{%- do record_info.update({key: (record_info[key] | default(0)) + 1}) %}
{%- endfor -%}
{{record_info}}"""
else:
return """
"""
jinja_env = Environment(
loader=FunctionLoader(my_template),
extensions=['jinja2.ext.do']
)
t = jinja_env.get_template('first_one')
print(t.render(records=records))
我知道它只是设置了一个用于实验的快速且肮脏的示例,但我认为这是一个更好的 样板 起点,因为它明确使用了 jinja Environment
和 Loaders
所以可以更容易地扩展,当我忘记这一切时不可避免地在几年后回到我自己的答案时,我会很感激 :D
import jinja2
from jinja2 import Template
records = [{'a':1,'b':1, 'c':1},{'a':1,'b':1, 'c':1}, {'a':2,'b':1, 'c':1}, {'a':3,'b':1, 'c':1}]
t = jinja2.Template("""
{% set record_info = dict() %}
{% for item in records %}
{% set key = str(item['a'])+str(item['b'])+str(item['c']) %}
{% if key in record_info %}
{% set record_info.key += 1 %}
{% else %}
{% set record_info.key = 1 %}
{% endif %}
{% endfor %}
{{record_info}}""")
这给了我:
Traceback (most recent call last):
File "<stdin>", line 11, in <module>
File "/Library/Python/2.7/site-packages/jinja2/environment.py", line 945, in __new__
return env.from_string(source, template_class=cls)
File "/Library/Python/2.7/site-packages/jinja2/environment.py", line 880, in from_string
return cls.from_code(self, self.compile(source), globals, None)
File "/Library/Python/2.7/site-packages/jinja2/environment.py", line 591, in compile
self.handle_exception(exc_info, source_hint=source_hint)
File "/Library/Python/2.7/site-packages/jinja2/environment.py", line 780, in handle_exception
reraise(exc_type, exc_value, tb)
File "<unknown>", line 6, in template
jinja2.exceptions.TemplateSyntaxError: expected token 'end of statement block', got '.'
我做错了什么?
我可以这样做,有什么改进吗?
records = [{'a':1,'b':1, 'c':1},{'a':1,'b':1, 'c':1}, {'a':2,'b':1, 'c':1}, {'a':3,'b':1, 'c':1}]
t = jinja2.Template("""
{% set record_info = dict() %}
{% for item in records %}
{% set key = item['a'] ~ ':' ~ item['b'] ~ ':' ~ item['c'] %}
{% if key in record_info %}
{% set _dummy = record_info.update( {key: record_info[key]+1 }) %}
{% else %}
{% set _dummy = record_info.update({ key:1 }) %}
{% endif %}
{% endfor %}
{{record_info}}""")
print t.render(records=records)
{u'1:1:1': 2, u'3:1:1': 1, u'2:1:1': 1}
您可以使用 "set".
{% set x = my_dict.__setitem__("key", "value") %}
然后您可以使用 my_dict,它将具有更新后的值(不要介意 x,它就在那里,不会引发错误)。这已经在另一个答案中,在 here.
中快速解决方案
现有的答案工作得很好,但既然你要求任何改进,我会尝试。
from jinja2 import Template
records = [{'a':1,'b':1, 'c':1},{'a':1,'b':1, 'c':1}, {'a':2,'b':1, 'c':1}, {'a':3,'b':1, 'c':1}]
t = Template("""
{%- set record_info = dict() %}
{%- for item in records %}
{%- set key = item['a'] ~ ':' ~ item['b'] ~ ':' ~ item['c'] %}
{%- do record_info.update({key: 1 if not record_info[key] else record_info[key]+1}) %}
{%- endfor -%}
{{record_info}}""",
extensions=['jinja2.ext.do']
)
print(t.render(records=records))
改进
- 显示导入 - 一些来到这里的 SO 用户可能是 Python 的新手,需要完整的上下文
- 使用 Python3 和
print()
函数(不是批评 - 我意识到这是在 2017 年,尽管from __future__
也可以) - 允许使用 do“表达式语句”扩展
- 使用
do
而不是设置_dummy
变量 - 避免使用
{%-
和-%}
的所有额外渲染 newlines/whitespace 将-
添加到那些 begin/end 标签中
其他变化
这些是否是改进是主观的——可读性是提高了还是受到了阻碍?
- 使用内联 if(三元)启用删除
else
子句
备注
使用默认值
这一行:
{%- do record_info.update({key: 1 if not record_info[key] else record_info[key]+1}) %}
也可以写成default
:
{%- do record_info.update({key: (record_info[key] | default(0)) + 1 }) %}
请注意,对现有 record_info[key]
的检查会通过管道传输到默认值,即使当密钥尚不存在时这是一个错误。
例如,这不起作用:
{%- do record_info.update({key: (record_info[key]+1 | default(1)) }) %}
...因为当它尝试计算 record_info[key]+1
时 record_info[key]
错误未被处理。
环境和装载机
文档建议使用 Loader
例如PackageLoader
启用模板继承等。在您的示例中,它看起来像是一个快速设置,因此我将忽略该要求。请注意,无论如何都要使用 Template constructor directly will create a shared 环境,而没有 Loader 或继承的好处。
如果您使用 PackageLoader
,您将有一个包名称和一个名为 templates
的文件夹用于加载它们。将模板放在单独的文件中也很好。
为了快速使用真正的加载器而无需那些单独的文件,FunctionLoader
很有用。您可以向函数添加更多模板字符串,并按名称 return 它们,例如
from jinja2 import Environment, FunctionLoader
records = [{'a':1,'b':1, 'c':1},{'a':1,'b':1, 'c':1}, {'a':2,'b':1, 'c':1}, {'a':3,'b':1, 'c':1}]
def my_template(name: str) -> str:
if name == 'first_one':
return """
{%- set record_info = dict() %}
{%- for item in records %}
{%- set key = item['a'] ~ ':' ~ item['b'] ~ ':' ~ item['c'] %}
{%- do record_info.update({key: (record_info[key] | default(0)) + 1}) %}
{%- endfor -%}
{{record_info}}"""
else:
return """
"""
jinja_env = Environment(
loader=FunctionLoader(my_template),
extensions=['jinja2.ext.do']
)
t = jinja_env.get_template('first_one')
print(t.render(records=records))
我知道它只是设置了一个用于实验的快速且肮脏的示例,但我认为这是一个更好的 样板 起点,因为它明确使用了 jinja Environment
和 Loaders
所以可以更容易地扩展,当我忘记这一切时不可避免地在几年后回到我自己的答案时,我会很感激 :D