繁体   English   中英

从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')

但是,我得到一个错误

追溯(最近一次呼叫最近):文件“ python”,第1行,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()取代,因此,您还必须发明自己的“参数”转义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每个( strvalue调用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"
}

但是,通常来说,如果您必须四处乱搞才能实现所需的功能-您可能首先要重新考虑这是否是正确的方法,并且可以以更简单的方式实现目标吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM