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
Ответы
Ответ 1
Вы не можете сериализовать это как json, json имеет гораздо менее гибкое представление о том, что считается диктофой, чем 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]}]'
Ответ 2
JSON поддерживает только строки как ключи. Вам нужно будет выбрать способ представления этих кортежей в виде строк.
Ответ 3
Вы можете просто использовать str((1,2))
как ключ, потому что json только ожидает ключи как строки, но если вы используете это, вам нужно будет использовать a[str((1,2))]
для получения значения.
Ответ 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()}
Смотрите: fooobar.com/questions/80100/...
Ответ 5
Вот один из способов сделать это. Это потребует, чтобы ключ был декодирован 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()
Я не претендую на эффективность этого метода. Мне понадобилось это для сохранения некоторых данных сопоставления джойстика в файл. Я хотел использовать что-то, что создавало бы полу-человеческий читаемый формат, чтобы его можно было редактировать, если это необходимо.
Ответ 6
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]))