为啥在使用 json.dumps 时,python dict 的 int 键会变成字符串?

Posted

技术标签:

【中文标题】为啥在使用 json.dumps 时,python dict 的 int 键会变成字符串?【英文标题】:Why do int keys of a python dict turn into strings when using json.dumps?为什么在使用 json.dumps 时,python dict 的 int 键会变成字符串? 【发布时间】:2013-06-10 13:49:03 【问题描述】:

根据this conversion table,当使用 JSON 模块进行序列化时,Python 整数会被写为 JSON 数字——正如我所期望和希望的那样。

我有一个带有整数键和整数值的字典:

>>> d = 1:2
>>> type(d.items()[0][0])
<type 'int'>
>>> type(d.items()[0][1])
<type 'int'>

当我使用json模块将这个序列化为JSON字符串时,值写成数字,而key写成字符串:

>>> json.dumps(d)
'"1": 2'

这不是我想要的行为,而且它似乎特别糟糕,因为它打破了 json.dumps/json.loads 往返:

>>> d == json.loads(json.dumps(d))
False

为什么会发生这种情况,有没有办法可以强制将密钥写为数字?

【问题讨论】:

JSON 键是 always 字符串。 ...而 JSON 使用字符串,因为它们与字节顺序无关。 如果 JSON 不是 严格 必需的,您可以使用 PyYAML 来代替 YAML:d = 1:2, 3:4; import yaml; yaml.safe_load(yaml.safe_dump(d)) == d 返回 True。一般来说,YAML 的“内联”样式看起来像更灵活的 json(键可以是数字,通常不必引用字符串)。我在这里使用safe_load,因为普通yaml.load 具有难以正确保护的特性(类的构造等); safe_load|dump 将支持的输入/输出集限制为原始类型(bool、int、float、string、list、set、dict),因此可以安全地用于任意输入。 不幸的是,往返行程不适用于 yaml.safe_dump,因为它将看起来像整数的字符串转换为整数。例如。试试 d = '1':'2' 上述往返问题的错误:bitbucket.org/xi/pyyaml/issue/21 【参考方案1】:

原因很简单,JSON does not allow integer keys.

object
    
     members  
members
    pair
    pair , members
pair
    string : value  # Keys *must* be strings.

关于如何绕过这个限制 - 您首先需要确保接收实现可以处理技术上无效的 JSON。然后,您可以替换所有引号或使用自定义序列化程序。

【讨论】:

与普通的 javascript 不同。所有的键都应该被引用。【参考方案2】:

如果你真的想要,你可以使用以下方法再次检查键是否可转换为整数:

def pythonify(json_data):
    for key, value in json_data.iteritems():
        if isinstance(value, list):
            value = [ pythonify(item) if isinstance(item, dict) else item for item in value ]
        elif isinstance(value, dict):
            value = pythonify(value)
        try:
            newkey = int(key)
            del json_data[key]
            key = newkey
        except TypeError:
            pass
        json_data[key] = value
    return json_data

【讨论】:

【参考方案3】:

如果可能,此函数将递归地将所有字符串键转换为整数键。如果不可能,键类型将保持不变。

我稍微调整了下面的JLT's 示例。对于我的一些巨大的嵌套字典,代码使字典的大小发生了变化,并以异常结束。无论如何,功劳归于 JLT!

def pythonify(json_data):

    correctedDict = 

    for key, value in json_data.items():
        if isinstance(value, list):
            value = [pythonify(item) if isinstance(item, dict) else item for item in value]
        elif isinstance(value, dict):
            value = pythonify(value)
        try:
            key = int(key)
        except Exception as ex:
            pass
        correctedDict[key] = value

    return correctedDict

【讨论】:

以上是关于为啥在使用 json.dumps 时,python dict 的 int 键会变成字符串?的主要内容,如果未能解决你的问题,请参考以下文章

python json.dumps()函数输出json格式,使用ensure_ascii参数对中文输入的支持

[转]python json.dumps 中的ensure_ascii 参数引起的中文编码

python json.dumps 中的ensure_ascii 参数引起的中文编码问题

python json.dumps 中的ensure_ascii 参数引起的中文编码问题

Python json.dumps 特殊数据类型的自定义序列化操作

使用 json.dumps 时 requests.post 失败 [重复]