2011-08-09 25 views
34

¿Hay alguna manera en Python para serializar un diccionario que está utilizando una tupla como clave:JSON serializar un diccionario con tuplas como clave

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

el simple uso de json.dumps (a), produce:

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

posible duplicado de [La mejor forma de codificar tuplas con json] (http://stackoverflow.com/questions/715550/best-way-to-encode-tuples-with-json) – agf

Respuesta

19

No se puede serializar como json, json tiene una idea mucho menos flexible sobre lo que cuenta como una clave dict que python.

Se podría transformar el mapeo en una secuencia de clave, pares de valores, algo como esto:

>>> 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]}]' 
7

JSON solo admite cadenas como claves. Tendrá que elegir una forma de representar esas tuplas como cadenas.

1

Esta es una manera de hacerlo. Se requiere la clave para ser decodificada JSON tras decodificar el diccionario principal y el diccionario completo re-secuenciado, pero es factible:

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() 

Yo no pretendo ninguna eficacia de este método. Lo necesitaba para guardar algunos datos de mapeo de joystick en un archivo. Quería usar algo que creara un formato semihumano legible para que pueda ser editado si es necesario.

3

Puede simplemente usar str((1,2)) como clave porque json solo espera que las claves sean como cadenas, pero si usa esto, tendrá que usar a[str((1,2))] para obtener el valor.

0

JSON sólo puede aceptar cadenas como claves para dict, lo que puede hacer, es reemplazar las llaves de tupla con una cuerda al igual que

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) 

Y que cuando se quiere leerlo, puede cambiar la llaves de vuelta a tuplas utilizando

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])) 
1
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()} 

Ver: https://stackoverflow.com/a/12337657/2455413

Cuestiones relacionadas