【问题标题】:Can I losslessly recover integer keys which json.dumps() has converted to strings?我可以无损地恢复 json.dumps() 已转换为字符串的整数键吗?
【发布时间】:2018-01-23 05:38:10
【问题描述】:

考虑这个sn-p:

>>> import json
>>> a = {1:'1'}
>>> json_a = json.dumps(a)
>>> json.loads(json_a)
{'1': '1'}

我的尝试是将 Python dict 传递给 json.dumps(),然后使用 json.loads() 将其取回。但这并没有发生,可能是因为 JSON alays 将键视为字符串。

还有其他方法可以保留原始密钥类型吗?

【问题讨论】:

标签: python json roundtrip


【解决方案1】:

json.dumps() 将 Python dicts 中的整数键转换为符合 JSON 标准的字符串键是有损:一旦完成,就无法判断原始键是整数 23 还是字符串'23'(除非该信息存储在其他地方)。

也就是说,您可以强制 json.loads() 尽可能将键转换为整数,方法是将适当的函数作为 object_pairs_hook 参数传递:

 def int_keys(ordered_pairs):
    result = {}
    for key, value in ordered_pairs:
        try:
            key = int(key)
        except ValueError:
            pass
        result[key] = value
    return result

用法:

>>> import json
>>> data = {1: '1', 2: '2', 3: '3'}
>>> text = json.dumps(data)
>>> text
'{"1": "1", "2": "2", "3": "3"}'
>>> json.loads(text, object_pairs_hook=int_keys)
{1: '1', 2: '2', 3: '3'}

对此进行扩展,还可以编写一个object_pairs_hook,它不仅可以转换整数,还可以转换json.dumps() 可能已转换为字符串的所有其他非字符串键:

SPECIAL = {
    "true": True,
    "false": False,
    "null": None,
}

def round_trip(ordered_pairs):
    result = {}
    for key, value in ordered_pairs:
        if key in SPECIAL:
            key = SPECIAL[key]
        else:
            for numeric in int, float:
                try:
                    key = numeric(key)
                except ValueError:
                    continue
                else:
                    break
        result[key] = value

用法:

>>> print(more_text)
{
  "2": 2,
  "3.45": 3.45,
  "true": true,
  "false": false,
  "null": null,
  "Infinity": Infinity,
  "-Infinity": -Infinity,
  "NaN": NaN
}
>>> json.loads(more_text, object_pairs_hook=round_trip)
{2: 2, 3.45: 3.45, True: True, False: False, None: None, inf: inf, -inf: -inf, nan: nan}

【讨论】:

  • 感谢您的回答。喜欢这个主意。但是,这个答案实际上会尽可能地将键转换为特定类型。我的意思是 {"1": 1} 总是被转换为 {1: 1} ,但我们不知道主键类型是整数还是字符串,我们只是试图盲目地转换它们。不是吗?但是,我的目标是在将其传递给 json.dumps 之前取回确切的密钥类型。
  • 例如,考虑这个:{1: 1}, {"2": 2}。根据这个答案,它将被评估为{1: 1}, {2: 2}。但是,目标是找回原来的{1: 1}, {"2": 2}。我希望现在很清楚。
  • @AhsanulHaque 正如我的答案顶部提到的那样,这是不可能的(因为json.dumps() 执行的转换只是丢弃了该类型信息),除非您a)将类型信息存储在其他地方,或者b) 发出实际上不是 JSON 的内容(如您的自我回答)。
  • @AhsanulHaque 很明显,是的。不过,这也是不可能的;-) 我的回答旨在作为“您可以管理的最佳”解决方法。
【解决方案2】:

我们可以用str(value)代替json.dumps(value),用ast.literal_eval()代替json.loads()

>>> a = {1: "1"}
>>> a_as_string = str(a)
>>> import ast 
>>> ast.literal_eval(a_as_string)
{1: '1'}

只是作为初始解决方案发布,期待更复杂的解决方案。

【讨论】:

  • 是的,当然,a_as_string 不是有效的 JSON。
  • ...这让我想知道这是否真的是问题的答案(这是您是否可以使整数键在 JSON 的往返过程中幸存下来)。使用 JSON 以外的东西当然是一种避免问题的方法,但这不一定与答案相同。
猜你喜欢
  • 1970-01-01
  • 2017-04-25
  • 2021-02-05
  • 2018-01-15
  • 1970-01-01
  • 2015-01-26
  • 2020-06-02
  • 2011-02-10
  • 1970-01-01
相关资源
最近更新 更多