Python's json module, converts int dictionary keys to strings
我发现运行以下命令时,python的json模块(自2.6起包含)将int字典键转换为字符串。
1 2 3 4 | >>> import json >>> releases = {1:"foo-v0.1"} >>> json.dumps(releases) '{"1":"foo-v0.1"}' |
有什么简单的方法可以将键保留为int,而无需在转储和加载时解析字符串。
我相信可以使用json模块提供的钩子,但这仍然需要解析。
我可能会忽略一个论点吗?
欢呼声,查兹
子问题:
感谢您的回答。 看到json就像我所担心的那样工作,是否有一种简单的方法可以通过解析转储的输出来传达密钥类型?
我还要注意执行转储的代码以及从服务器下载json对象并加载它的代码都是我编写的。
这是可能困扰您的各种映射集合之间的细微差别之一。 JSON将键视为字符串; Python支持仅在类型上不同的独特键。
在Python中(显然在Lua中),映射的键(分别是字典或表)是对象引用。在Python中,它们必须是不可变的类型,或者它们必须是实现
在Perl,Javascript,awk和许多其他语言中,哈希,关联数组的键或给定语言所调用的键都是字符串(或Perl中的"标量")。在perl
JSON从Java序列化技术开始。 (JSON表示JavaScript对象表示法。)自然地,它为其映射表示法实现了与其映射语义一致的语义。
如果序列化的两端都将是Python,那么最好使用咸菜。如果您确实需要将这些从JSON转换回本机Python对象,我想您有两种选择。首先,如果字典查找失败,您可以尝试(
不,JavaScript中没有数字键之类的东西。所有对象属性都将转换为String。
1 2 3 | var a= {1: 'a'}; for (k in a) alert(typeof k); // 'string' |
这可能会导致一些奇怪的行为:
1 2 3 4 | a[999999999999999999999]= 'a'; // this even works on Array alert(a[1000000000000000000000]); // 'a' alert(a['999999999999999999999']); // fail alert(a['1e+21']); // 'a' |
JavaScript对象并不是真正正确的映射,因为您会在Python之类的语言中理解它,并且使用非String的键会导致怪异。这就是为什么JSON总是显式地将键写为字符串的原因,即使它看起来不必要。
另外,您也可以尝试在使用json进行编码的同时将字典转换为[(k1,v1),(k2,v2)]格式的列表,并在将其解码后将其转换回字典。
1 2 3 4 5 6 | >>>> import json >>>> json.dumps(releases.items()) '[[1,"foo-v0.1"]]' >>>> releases = {1:"foo-v0.1"} >>>> releases == dict(json.loads(json.dumps(releases.items()))) True |
code>
我相信这将需要做更多的工作,例如具有某种标志,以识别从json解码回去后要转换为字典的所有参数。
回答您的子问题:
可以使用
1 2 3 4 | def jsonKeys2int(x): if isinstance(x, dict): return {int(k):v for k,v in x.items()} return x |
此功能也适用于嵌套字典,并使用字典理解。
如果您也想强制转换值,请使用:
1 2 3 4 | def jsonKV2int(x): if isinstance(x, dict): return {int(k):(int(v) if isinstance(v, unicode) else v) for k,v in x.items()} return x |
它测试值的实例并仅在它们是字符串对象(确切地说是unicode)时才将其强制转换。
这两个函数均假定键(和值)为整数。
谢谢:
如何在字典理解中使用if / else?
在字典中将字符串键转换为int
我被同样的问题咬了。正如其他人指出的那样,在JSON中,映射键必须是字符串。您可以做两件事之一。您可以使用不太严格的JSON库,例如demjson,它允许整数字符串。如果没有其他程序(或其他语言的其他语言)无法读取它,那么您应该可以。或者,您可以使用其他序列化语言。我不建议泡菜。它很难阅读,并非旨在确保安全。相反,我建议使用YAML,它几乎是JSON的超集,并且确实允许整数键。 (至少PyYAML这样做。)
通过使用
1 2 | import ast ast.literal_eval(string) |
我对Murmel的答案做了一个非常简单的扩展,我认为它首先可以被JSON转储,因此可以在相当随意的字典(包括嵌套的字典)上使用。任何可以解释为整数的键都将转换为int。毫无疑问,这不是很有效,但是它可以实现我存储到json字符串和从json字符串加载的目的。
1 2 3 4 5 6 7 8 9 10 11 | def convert_keys_to_int(d: dict): new_dict = {} for k, v in d.items(): try: new_key = int(k) except ValueError: new_key = k if type(v) == dict: v = _convert_keys_to_int(v) new_dict[new_key] = v return new_dict |
假设原始字典中的所有键都是整数(如果可以将它们强制转换为int),则在将其存储为json后将返回原始字典。
例如
1 2 3 | >>>d = {1: 3, 2: 'a', 3: {1: 'a', 2: 10}, 4: {'a': 2, 'b': 10}} >>>convert_keys_to_int(json.loads(json.dumps(d))) == d True |
这是我的解决方案!我使用了
1 2 3 4 5 6 | >>> 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的过滤器。您也可以将
您可以自己编写
1 | assert dumps({1:"abc"}) == '{1:"abc"}' |