如何使用 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(。

感谢皮尔斯的主张:

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}

除了 Pierce 响应之外,我认为您可以使用 json.loadsobject_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)部分。

正如我们在评论中建立的那样,没有现有的功能可以为您执行此操作。我通读了文档和一些关于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}

对于我的解决方案,我使用了object_hook,这在嵌套json时很有用

>>> import json
>>> json_data = '{"1": "one", "2": {"-3": "minus three", "4": "four"}}'
>>> py_dict = json.loads(json_data, object_hook=lambda d: {int(k) if k.lstrip('-').isdigit() else k: v for k, v in d.items()})
>>> py_dict
{1: 'one', 2: {-3: 'minus three', 4: 'four'}}

有一个过滤器仅用于将 json 键解析为 int。您也可以使用int(v) if v.lstrip('-').isdigit() else v来筛选 json 值。

除了@juanra,因此@Pierce Darragh之外,我还添加了字符串布尔值的转换。我的示例是从 XML 转换而来的字典,其中包含'true''false',这些字典不会作为 JSON 布尔True加载,并且会自动False建议的答案。

def _decode(o):
if isinstance(o, str):
if o.lower() == 'true':
return True
elif o.lower() == 'false':
return False
else:
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

根据您的需要,您还可以在 Python 中从字符串转换为布尔值中包含其他字符串进行布尔转换?

def convert_to_int(params):
for key in params.keys():
if isinstance(params[key], dict):
convert_to_int(params[key])
elif isinstance(params[key], list):
for item in params[key]:
if not isinstance(item, (dict, list)):
item = int(item)
else:
convert_to_int(item)
else:
params[key] = int(params[key])
return params

print convert_to_int({'a': '3', 'b': {'c': '4', 'd': {'e': 5}, 'f': [{'g': '6'}]}})

相关内容

  • 没有找到相关文章

最新更新