2012-07-19 6 views
25

Ho notato questo problema quando un computer con Ubuntu è stato aggiornato di recente e la versione predefinita di Python è stata modificata in 2.7.Perché json.dumps (list (np.arange (5))) fallisce mentre json.dumps (np.arange (5) .tolist()) funziona

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 

C'è una differenza tra list() e il metyst di tolist() di una matrice numpy?

+1

Sto vedendo un problema simile, dove non posso 'json.dumps()' una variabile np.int64. Tuttavia, funziona per me in Python 2.7.9 ma non in 3.4. –

risposta

23

Sembra che il metodo tolist() trasformi il numpy int32 (o qualsiasi altra dimensione) in uno int, che JSON sa cosa fare 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'> 

Come i documenti dicono per tolist():

Ritorna l'array come una lista (eventualmente inserita).

Restituisce una copia dei dati dell'array come elenco (nidificato) di Python. Gli articoli vengono convertiti nel tipo Python compatibile più vicino.

L'ultima riga fa la differenza qui.

+0

Sai se questo è un cambiamento recente? Il codice funzionava prima che il sistema venisse aggiornato. – azeey

+0

Non sono sicuro, temo, non sono nemmeno sicuro se il cambiamento fosse in numpy (diciamo un cambio di nome) o sul lato JSON di Python (forse era più difficile trattare tipi sconosciuti?) – DSM

+0

[Soluzione semplice] (http://stackoverflow.com/questions/8230315/python-sets-are-not-json-serializable) passando esplicitamente un [handler predefinito] (http://docs.python.org/2/library/json. html # json.dumps) per oggetti non serializzabili. –

24

Poiché gli elementi di un array NumPy non sono interi nativi, ma di propri tipi di NumPy:

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

È possibile utilizzare un costume JSONEncoder per supportare il tipo ndarray restituito da 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

Il problema è che con il primo non si ottiene un int. Hai un numpy.int64. Questo non può essere serializzato.

Problemi correlati