如何使用 json.loads 将字符串 int JSON 转换为真正的 int

新手上路,请多包涵

我正在尝试使用 json.loads 将表示 JSON 对象的字符串转换为真正的 JSON 对象,但它不会转换整数:

(在初始字符串中,整数始终是字符串)

 $> python
Python 2.7.9 (default, Aug 29 2016, 16:00:38)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import json
>>> c = '{"value": "42"}'
>>> json_object = json.loads(c, parse_int=int)
>>> json_object
{u'value': u'42'}
>>> json_object['value']
u'42'
>>>

而不是 {u'value': u'42'} 我希望它变成 {u'value': 42} 。我知道我可以遍历整个对象,但我不想这样做,手动执行它并不是很有效,因为这个 parse_int 参数存在( https://docs.python.org /2/library/json.html#json.loads )。

感谢 Pierce 的提议:

 Python 2.7.9 (default, Aug 29 2016, 16:00:38)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import json
>>>
>>> class Decoder(json.JSONDecoder):
...     def decode(self, s):
...         result = super(Decoder, self).decode(s)
...         return self._decode(result)
...     def _decode(self, o):
...         if isinstance(o, str) or isinstance(o, unicode):
...             try:
...                 return int(o)
...             except ValueError:
...                 try:
...                     return float(o)
...                 except ValueError:
...                     return o
...         elif isinstance(o, dict):
...             return {k: self._decode(v) for k, v in o.items()}
...         elif isinstance(o, list):
...             return [self._decode(v) for v in o]
...         else:
...             return o
...
>>>
>>> c = '{"value": "42", "test": "lolol", "abc": "43.4",  "dcf": 12, "xdf": 12.4}'
>>> json.loads(c, cls=Decoder)
{u'test': u'lolol', u'dcf': 12, u'abc': 43.4, u'value': 42, u'xdf': 12.4}

原文由 Léo 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 810
2 个回答

正如我们在评论中所确定的那样,没有现有的功能可以为您执行此操作。我通读了文档和 JSONDecoder 上的一些示例,它似乎也不会在不处理数据两次的情况下做你想做的事。

那么,最好的选择是这样的:

 class Decoder(json.JSONDecoder):
    def decode(self, s):
        result = super().decode(s)  # result = super(Decoder, self).decode(s) for Python 2.x
        return self._decode(result)

    def _decode(self, o):
        if isinstance(o, str) or isinstance(o, unicode):
            try:
                return int(o)
            except ValueError:
                return o
        elif isinstance(o, dict):
            return {k: self._decode(v) for k, v in o.items()}
        elif isinstance(o, list):
            return [self._decode(v) for v in o]
        else:
            return o

这有处理 JSON 对象两次的缺点 — 一次在 super().decode(s) 调用中,然后再次递归遍历整个结构以修复问题。另请注意, 这会将任何看起来像整数的东西转换为 int 。请务必适当考虑这一点。

要使用它,您需要执行以下操作:

 >>> c = '{"value": "42"}'
>>> json.loads(c, cls=Decoder)
{'value': 42}

原文由 Pierce Darragh 发布,翻译遵循 CC BY-SA 4.0 许可协议

除了 Pierce 响应之外,我认为您可以使用 json.loads object_hook 参数代替 cls 一个,因此您不需要遍历 json 对象两次。

例如:

 def _decode(o):
    # Note the "unicode" part is only for python2
    if isinstance(o, str) or isinstance(o, unicode):
        try:
            return int(o)
        except ValueError:
            return o
    elif isinstance(o, dict):
        return {k: _decode(v) for k, v in o.items()}
    elif isinstance(o, list):
        return [_decode(v) for v in o]
    else:
        return o

# Then you can do:
json.loads(c, object_hook=_decode)

正如@ZhanwenChen 在评论中指出的那样,上面的代码是针对 python2 的。对于 python3 ,您需要删除第一个 if 条件中的 or isinstance(o, unicode) 部分。

原文由 juanra 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题