假设我有一个(大)字典列表,例如:
my_list = [
{
"foo": "bar",
"foobar": "barfoo",
"something": 1,
"useless_bool": True
},
{
"foo": "rab",
"foobar": "oofrab",
"something": 1,
"useless_str": "different_value"
},
...
]
此列表包含数千个字典,每个字典可以有数百个个键。我还有一个 Jinja 模板,例如:
jinja_template = jinja2.Environment().from_string(
"{{ foo }} - {{ foobar }} - {{ something }}"
)
对于列表中的每个字典,我想添加一个包含渲染的 Jinja 模板的新键(使用其他现有键),并删除所有其他键。以这样的方式结束:
[
{
"new_key": "bar - barfoo - 1"
},
{
"new_key": "rab - oofrab - different_value"
},
...
]
到目前为止,我做了一个(愚蠢的)循环来做到这一点:
import jinja2
jinja2.Environment().from_string("{{ foo }} - {{ foobar }} - {{ something }}")
for item in my_list:
# Render the new value
rendered_value = new_message_template.render(**item)
# Remove all existing keys
item.clear()
# Set the new key/value
item["new_key"] = rendered_value
这有效。
但是考虑到这个列表包含数千个字典,每个字典都有数百个键,在性能和执行时间方面是否有更优化的方法来执行此操作?
有几件事:
jinja2.Environment().from_string("{{ foo }} - {{ foobar }} - {{ something }}")
此表达式目前被忽略。我假设这应该分配给new_message_template.render
您正在对字典进行就地突变。为什么?只需创建一个新的转换后的字典列表即可。
Jinja 2 模板渲染受 I/O 限制,这使其成为基于线程的并发的良好候选者。线程对于 I/O 密集型任务很有用,因为 python 线程在等待 I/O 操作完成时并发运行。您可以使用
ThreadPoolExecutor
import jinja2
from concurrent.futures import ThreadPoolExecutor
new_message_template = jinja2.Environment().from_string("{{ foo }} - {{ foobar }} - {{ something }}")
def process_item(item):
rendered_value = new_message_template.render(**item)
return {"new_key": rendered_value}
def process_data(data):
with ThreadPoolExecutor() as executor:
result = list(executor.map(process_item, data))
return result
# Example data
my_list = [
{"foo": "value1", "foobar": "value2", "something": "value3"},
{"foo": "hello", "foobar": "world", "something": "!"}
]
new_list = process_data(my_list)
print(new_list)