json序列化一个以元组为关键字的字典

时间:2011-08-09 19:11:54

标签: python json

Python中是否有一种方法可以序列化使用元组作为键的字典:

a={(1,2):'a'}

简单地使用json.dumps(a),产生:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.6/json/__init__.py", line 230, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib/python2.6/json/encoder.py", line 367, in encode
    chunks = list(self.iterencode(o))
  File "/usr/lib/python2.6/json/encoder.py", line 309, in _iterencode
    for chunk in self._iterencode_dict(o, markers):
  File "/usr/lib/python2.6/json/encoder.py", line 268, in _iterencode_dict
    raise TypeError("key {0!r} is not a string".format(key))
TypeError: key (1, 2) is not a string

7 个答案:

答案 0 :(得分:29)

你无法将其序列化为json,json对于什么算作dict键而不是python的想法要灵活得多。

您可以将映射转换为一系列键值对,如下所示:

>>> import json
>>> def remap_keys(mapping):
...     return [{'key':k, 'value': v} for k, v in mapping.iteritems()]
... 
>>> json.dumps(remap_keys({(1, 2): 'foo'}))
'[{"value": "foo", "key": [1, 2]}]'

答案 1 :(得分:8)

JSON仅支持字符串作为键。您需要选择一种将这些元组表示为字符串的方法。

答案 2 :(得分:6)

您可以使用str((1,2))作为密钥,因为json只希望将密钥作为字符串,但如果您使用此密钥,则必须使用a[str((1,2))]来获取值。

答案 3 :(得分:4)

from json import load, dump
from ast import literal_eval

x={ (0,1):'la-la la', (0,2):'extricate' }

# save: convert each tuple key to a string before saving as json object
with open('/tmp/test', 'w') as f: dump({str(k):v for k, v in x.items()}, f)

# load in two stages:#
# (i) load json object
with open('/tmp/test', 'r') as f: obj = load(f)

# (ii) convert loaded keys from string back to tuple
d={literal_eval(k):v for k, v in obj.items()}

请参阅:https://stackoverflow.com/a/12337657/2455413

答案 4 :(得分:1)

这是一种方法。在主字典被解码并且整个字典重新排序之后,它将要求密钥被json解码,但它是可行的:

    import json

    def jsonEncodeTupleKeyDict(data):
        ndict = dict()
        # creates new dictionary with the original tuple converted to json string
        for key,value in data.iteritems():
            nkey = json.dumps(key)
            ndict[nkey] =  value

        # now encode the new dictionary and return that
        return json.dumps(ndict)

    def main():
        tdict = dict()
        for i in range(10):
            key = (i,"data",5*i)
            tdict[key] = i*i

        try:
            print json.dumps(tdict)
        except TypeError,e:
            print "JSON Encode Failed!",e

        print jsonEncodeTupleKeyDict(tdict)

    if __name__ == '__main__':
        main()

我对此方法的效率没有任何要求。我需要这个来将一些操纵杆映射数据保存到文件中。我想使用能够创建半人类可读格式的内容,以便在需要时进行编辑。

答案 5 :(得分:1)

json只能接受字符串作为dict的键, 你可以做的是用字符串替换元组键

with open("file", "w") as f:
    k = dic.keys() 
    v = dic.values() 
    k1 = [str(i) for i in k]
    json.dump(json.dumps(dict(zip(*[k1,v]))),f) 

并且当您想要阅读它时,您可以使用

将密钥更改回元组
with open("file", r) as f:
    data = json.load(f)
    dic = json.loads(data)
    k = dic.keys() 
    v = dic.values() 
    k1 = [eval(i) for i in k] 
    return dict(zip(*[k1,v])) 

答案 6 :(得分:0)

您实际上不能将元组序列化为 json 的键,但是您可以将元组转换为字符串并在反序列化文件后恢复它。

with_tuple = {(0.1, 0.1): 3.14} ## this will work in python but is not serializable in json
{(0.1, 0.1): 3.14}

但是你不能用json序列化它。但是,您可以使用

with_string = {str((0.1, 0.1))[1:-1]: 3.14} ## the expression [1,-1] removes the parenthesis surrounding the tuples in python. 

{'0.1, 0.1': 3.14} # This is serializable

稍加作弊,您将通过分别处理每个键(作为 str)来恢复原始元组(在反序列化整个文件之后)

tuple(json.loads("["+'0.1, 0.1'+"]")) ## will recover the tuple from string
(0.1, 0.1)

使用 json.loads 将字符串转换为元组有点重载,但它会起作用。封装它,你就完成了。

安静并快乐地编码!

尼古拉斯