从 dict 解码为 str 时无法格式化 Python 字符串
Unable to format Python string while decoding from dict to 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')
但是,我得到一个错误
Traceback (most recent call last): File "python", line 1, in
KeyError: '"_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()
取代,所以你也必须发明你自己的 'parameter' 转义(确保它不会显示为 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}
) 从扩展键中获取所需的参数。
UPDATE:您甚至不需要递归最后一个数据,因为 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"
}
但是,一般来说,如果您必须 修改 您的系统以实现您想要的效果 - 您可能首先要重新考虑这是否是正确的方法,您的方法是否可行? objective有没有更简单的方式实现?
我有一个字典,我将其编码为这样的字符串:
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')
但是,我得到一个错误
Traceback (most recent call last): File "python", line 1, in KeyError: '"_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()
取代,所以你也必须发明你自己的 'parameter' 转义(确保它不会显示为 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}
) 从扩展键中获取所需的参数。
UPDATE:您甚至不需要递归最后一个数据,因为 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"
}
但是,一般来说,如果您必须 修改 您的系统以实现您想要的效果 - 您可能首先要重新考虑这是否是正确的方法,您的方法是否可行? objective有没有更简单的方式实现?