Python的json模块,将int字典键转换为字符串

z4iuyo4d  于 2022-12-27  发布在  Python
关注(0)|答案(9)|浏览(226)

我发现当下面的代码运行时,python的json模块(从2.6开始就包含了)会将int字典的键转换成字符串。

>>> import json
>>> releases = {1: "foo-v0.1"}
>>> json.dumps(releases)
'{"1": "foo-v0.1"}'

有没有什么简单的方法可以将键保留为int,而不需要在转储和加载时解析字符串。我相信使用json模块提供的钩子是可能的,但同样这仍然需要解析。有没有可能我忽略了一个参数?
子问题:谢谢你的回答。看到json像我担心的那样工作,有没有一种简单的方法可以通过解析转储的输出来传递键类型?我还应该注意到,执行转储的代码和从服务器下载json对象并加载它的代码都是我写的。

r7knjye2

r7knjye21#

这是各种Map集合之间的细微差别之一,JSON将键视为字符串; Python支持不同的键,只是类型不同。
在Python中(显然在Lua中),Map(分别是字典或表)的键是对象引用。在Python中,它们必须是不可变类型,或者它们必须是实现__hash__方法的对象。(Lua文档建议它自动使用对象的ID作为哈希/键,甚至对于可变对象也是如此,并依赖于字符串实习来确保等价的字符串Map到相同的对象)。
在Perl,Javascript,awk和许多其他语言中,散列,关联数组或任何给定语言中的键都是字符串(或Perl中的“标量”).在Perl中,$foo{1}, $foo{1.0}, and $foo{"1"}都是对%foo中相同Map的引用--键被 * 评估 * 为标量!
JSON最初是一种Javascript序列化技术。(JSON代表JavaS脚本ObjectN旋转。)自然,它实现了与其Map语义一致的Map表示法的语义。
如果序列化的两端都是Python,那么最好使用pickle。如果你真的需要将它们从JSON转换回原生Python对象,我想你有几个选择。首先,你可以尝试(try: ... except: ...),以便在字典查找失败的情况下将任何键转换为数字。如果你在另一端加上代码(这个JSON数据的序列化器或生成器),那么您可以让它对每个键值执行JSON序列化---将它们作为键列表提供。(然后,Python代码将首先遍历键列表,将它们示例化/反序列化为原生Python对象......然后使用它们访问Map之外的值)。

ztigrdn8

ztigrdn82#

不,JavaScript中没有Number键,所有对象属性都转换为String。

var a= {1: 'a'};
for (k in a)
    alert(typeof k); // 'string'

这可能会导致一些看似奇怪的行为:

a[999999999999999999999]= 'a'; // this even works on Array
alert(a[1000000000000000000000]); // 'a'
alert(a['999999999999999999999']); // fail
alert(a['1e+21']); // 'a'

JavaScript对象并不是像Python这样的语言中所理解的那样真正正确的Map,使用非String的键会导致奇怪的结果,这就是为什么JSON总是显式地将键写为字符串,即使在看起来没有必要的地方。

k10s72fa

k10s72fa3#

回答您的子问题:
它可以通过使用json.loads(jsonDict, object_hook=jsonKeys2int)来完成

def jsonKeys2int(x):
    if isinstance(x, dict):
            return {int(k):v for k,v in x.items()}
    return x

此函数也适用于嵌套字典,并使用字典解析。
如果您还想强制转换这些值,请使用:

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)时才强制转换它们。
这两个函数都假定键(和值)为整数。
感谢:
How to use if/else in a dictionary comprehension?
Convert a string key to int in a Dictionary

7eumitmz

7eumitmz4#

或者,您也可以尝试在使用json编码时将dictionary转换为[(k1,v1),(k2,v2)]格式的列表,并在解码后将其转换回dictionary。

>>>> import json
>>>> json.dumps(releases.items())
    '[[1, "foo-v0.1"]]'
>>>> releases = {1: "foo-v0.1"}
>>>> releases == dict(json.loads(json.dumps(releases.items())))
     True

我相信这将需要一些更多的工作,如有某种标志,以确定什么所有参数转换到字典后,解码从json回来。

siotufzp

siotufzp5#

我也遇到过同样的问题。正如其他人所指出的,在JSON中,Map键必须是字符串。你可以做两件事中的一件。你可以使用一个不太严格的JSON库,比如demjson,它允许整数字符串。如果没有其他程序(或者其他语言中没有其他人)会读它,那么你应该没问题。或者你可以使用不同的序列化语言。我不建议pickle。它很难读,而且是not designed to be secure。相反,我建议YAML。它(几乎)是JSON的超集,并且允许整数键(至少PyYAML允许)。

jv2fixgn

jv2fixgn6#

下面是我的解决方案!我使用了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值。

sg3maiej

sg3maiej7#

使用str(dict)将字典转换为字符串,然后执行以下操作将其转换回dict:

import ast
ast.literal_eval(string)
evrscar2

evrscar28#

我对Murmel的答案做了一个非常简单的扩展,我认为这将适用于一个相当任意的字典(包括嵌套字典),假设它可以被JSON首先转储。任何可以被解释为整数的键都将被转换为int。毫无疑问,这不是很有效,但它适用于我的目的,即存储到json字符串和从json字符串加载。

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

假设原始dict中的所有键都是整数,如果它们可以被强制转换为int,那么这将在存储为json后返回原始字典。

>>>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
oxosxuxt

oxosxuxt9#

[NSFW]您可以自己编写json.dumps,下面是djson的示例:encoder.py。您可以这样使用它:

assert dumps({1: "abc"}) == '{1: "abc"}'

相关问题