无法格式化 Python 字符串,同时从字典解码为 str



>我有一个字典,我将其编码为字符串:

import json
template = json.dumps({
'_index': '{0}',
'_type': '{1}',
'_id': '{2}',
'_source': {
'doc': '{3}',
'doc_as_upsert': True
}
})

现在,我尝试按照这里提到的新python约定对其进行格式化:https://pyformat.info/

print template.format('one','two','three','four')

但是,我收到一个错误

回溯(最近最后一次调用(:文件 "python",第 1 行,在 密钥错误:"_type">

我在这里做错了什么?

问题源于 JSON 中的大括号 - 您需要对它们进行双重转义才能使str.format()正常工作,例如:

import json
template = json.dumps({
'_index': '{0}',
'_type': '{1}',
'_id': '{2}',
'_source': {
'doc': '{3}',
'doc_as_upsert': True
}
})
template = template.replace("{", "{{").replace("}", "}}")
print(template.format('one','two','three','four'))

它不会再出错,但它也会转义你的参数大括号,这样它们就不会被str.format()替换,所以你也必须发明自己的"参数"转义(确保它不会出现为 JSON 的标记代码,就像大括号一样(,例如使用<>代替:

import json
template = json.dumps({
'_index': '<0>',
'_type': '<1>',
'_id': '<2>',
'_source': {
'doc': '<3>',
'doc_as_upsert': True
}
})
template = template.replace("{", "{{").replace("}", "}}").replace("<", "{").replace(">", "}")
print(template.format('one', 'two', 'three', 'four'))

但是,在将数据转换为 JSON 之前直接替换数据要好得多。您可以在dict中的每个(str(value上单独调用str.format(),将包含所有参数的dict传递给它并使用命名参数(即{one}( 从扩展键中获取所需的参数。

更新:您甚至不需要递归最后一个数据,因为json序列化程序无论如何都会递归,但不幸的是,json模块并不容易交换字符串序列化的默认行为,因此您必须进行一些猴子修补:

from json import dumps, encoder
def template_json(data, args, **kwargs):
json_s1, json_s2 = encoder.encode_basestring, encoder.encode_basestring_ascii
encoder.encode_basestring = lambda s: json_s1(s.format(**args))
encoder.encode_basestring_ascii = lambda s: json_s2(s.format(**args))
try:
return dumps(data, **kwargs)
finally:
encoder.encode_basestring, encoder.encode_basestring_ascii = json_s1, json_s2

它本质上暂时将内部 JSON 字符串构建方法包装为首先应用格式化的方法,然后恢复所有内容,以便可能依赖于json模块的其他函数不会出现意外行为(尽管这里也有一点危险 - 这不是线程安全的(。由于它将逐个读取元素,因此我们无法真正使用位置格式,因此这使用上面建议的命名格式。您可以将其测试为:

data = {
'_index': '{one}',
'_type': '{two}',
'_id': '{three}',
'_source': {
'doc': '{four}',
'doc_as_upsert': True,
}
}
template_vars = {"one": "value 1", "two": "value 2", "three": "value 3", "four": "value 4"}
print(template_json(data, template_vars, indent=4))

结果是:

{
"_source": {
"doc": "value 4",
"doc_as_upsert": true
},
"_index": "value 1",
"_id": "value 3",
"_type": "value 2"
}

但是,一般来说,如果你必须破解你的系统来实现你想要的东西 - 你可能想重新考虑这是否是正确的方法,你的目标能以更简单的方式实现吗?

最新更新