关于python:json以元组为键序列化字典

json serialize a dictionary with tuples as key

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

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

只需使用json.dumps(a),就会产生:

1
2
3
4
5
6
7
8
9
10
11
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


您不能将其序列化为json,json对于什么算作dict键要比python灵活得多。

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

1
2
3
4
5
6
>>> 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]}]'

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


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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
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


json只能接受字符串作为字典的键,
您可以做的是用这样的字符串替换元组键

1
2
3
4
5
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)

而且,当您要阅读它时,可以使用以下命令将键改回元组

1
2
3
4
5
6
7
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]))

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    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()

我不主张这种方法的任何效率。我需要用它来保存一些操纵杆映射数据到文件。我想使用可以创建半人类可读格式的东西,以便在需要时可以对其进行编辑。