2012-07-19 5 views
25

Me di cuenta de este problema cuando una computadora con Ubuntu se actualizó recientemente y la versión predeterminada de Python cambió a 2.7.¿Por qué json.dumps (list (np.arange (5))) falla mientras que json.dumps (np.arange (5) .tolist()) funciona

import json 
import numpy as np 

json.dumps(list(np.arange(5))) # Fails, throws a "TypeError: 0 is not JSON serializable" 
json.dumps(np.arange(5).tolist()) # Works 

¿Hay una diferencia entre list() y el tolist() methd de una matriz numpy?

+1

Veo un problema similar, donde no puedo 'json.dumps()' una variable np.int64. Sin embargo, funciona para mí en Python 2.7.9 pero no en 3.4. –

Respuesta

23

Parece que el método tolist() convierte el numpy int32 (o el tamaño que tenga) de nuevo en un int, que JSON sabe qué hacer con:

>>> list(np.arange(5)) 
[0, 1, 2, 3, 4] 
>>> type(list(np.arange(5))) 
<type 'list'> 
>>> type(list(np.arange(5))[0]) 
<type 'numpy.int32'> 
>>> np.arange(5).tolist() 
[0, 1, 2, 3, 4] 
>>> type(np.arange(5).tolist()) 
<type 'list'> 
>>> type(np.arange(5).tolist()[0]) 
<type 'int'> 

Como dicen los documentos de tolist():

devolver la matriz como una lista (posiblemente anidada).

Devuelve una copia de los datos de la matriz como una lista de Python (anidada). Los elementos de datos se convierten al tipo de Python compatible más cercano.

La última línea hace la diferencia aquí.

+0

¿Sabes si esto es un cambio reciente? El código solía funcionar antes de que el sistema se actualizara. – azeey

+0

No estoy seguro, ni siquiera estoy seguro de si el cambio fue nítido (digamos un cambio de nombre de tipo) o en el lado de Python JSON (¿quizás solía ser más difícil tratar con tipos desconocidos?) – DSM

+0

[Solución simple] (http://stackoverflow.com/questions/8230315/python-sets-are-not-json-serializable) pasando explícitamente un [controlador predeterminado] (http://docs.python.org/2/library/json. html # json.dumps) para objetos no serializables. –

24

Debido a que los elementos de una matriz NumPy no son enteros nativos, sino de los propios tipos de numpy:

>>> type(np.arange(5)[0]) 
<type 'numpy.int64'> 

Usted puede utilizar una costumbre JSONEncoder para apoyar el tipo ndarray devuelto por arange:

import numpy as np 
import json 

class NumPyArangeEncoder(json.JSONEncoder): 
    def default(self, obj): 
     if isinstance(obj, np.ndarray): 
      return obj.tolist() # or map(int, obj) 
     return json.JSONEncoder.default(self, obj) 

print(json.dumps(np.arange(5), cls=NumPyArangeEncoder)) 
1

El problema es que con la primera no se obtiene un int. Obtienes un numpy.int64. Eso no puede ser serializado.

Cuestiones relacionadas