2014-09-15 3 views
3

В python 3.4.0, используя json.dumps(), я бросаю мне TypeError в одном случае, но работает как шарм в другом случае (что, по-моему, эквивалентно первому).Weird TypeError от json.dumps

У меня есть dict, где ключи являются строками, а значения - числами и другими dicts (например, {'x': 1.234, 'y': -5.678, 'z': {'a': 4, 'b': 0, 'c': -6}}).

Это не удается (StackTrace не от этого конкретного фрагмента кода, но из моего большего сценария, который я не буду вставлять здесь, но это essentialy то же самое):

>>> x = dict(foo()) # obtain the data and make a new dict of it to really be sure 
>>> import json 
>>> json.dumps(x) 
Traceback (most recent call last): 
    File "/mnt/data/gandalv/progs/pycharm-3.4/helpers/pydev/pydevd.py", line 1733, in <module> 
    debugger.run(setup['file'], None, None) 
    File "/mnt/data/gandalv/progs/pycharm-3.4/helpers/pydev/pydevd.py", line 1226, in run 
    pydev_imports.execfile(file, globals, locals) # execute the script 
    File "/mnt/data/gandalv/progs/pycharm-3.4/helpers/pydev/_pydev_execfile.py", line 38, in execfile 
    exec(compile(contents+"\n", file, 'exec'), glob, loc) #execute the script 
    File "/mnt/data/gandalv/School/PhD/Other work/Krachy/code/recalculate.py", line 54, in <module> 
    ls[1] = json.dumps(f) 
    File "/usr/lib/python3.4/json/__init__.py", line 230, in dumps 
    return _default_encoder.encode(obj) 
    File "/usr/lib/python3.4/json/encoder.py", line 192, in encode 
    chunks = self.iterencode(o, _one_shot=True) 
    File "/usr/lib/python3.4/json/encoder.py", line 250, in iterencode 
    return _iterencode(o, 0) 
    File "/usr/lib/python3.4/json/encoder.py", line 173, in default 
    raise TypeError(repr(o) + " is not JSON serializable") 
TypeError: 306 is not JSON serializable 

306 является одним из значений в одном из внутренних запросов в x. Это не всегда одно и то же число, иногда это другое число, содержащееся в dict, по-видимому, из-за неупорядоченности dict.

Однако, это работает как шарм:

>>> x = foo() # obtain the data and make a new dict of it to really be sure 
>>> import ast 
>>> import json 
>>> x2 = ast.literal_eval(repr(x)) 
>>> x == x2 
True 
>>> json.dumps(x2) 
"{...}" # the json representation of dict as it should be 

Может кто-нибудь, пожалуйста, скажите мне, почему это происходит и что может быть причиной? Самая запутанная часть состоит в том, что эти два dicts (исходный и тот, который был получен путем оценки представления исходного) равны, но функция dumps() ведет себя по-разному для каждого из них.

+4

Вы уверены это фактическое целое число, а не какой-либо другой объект, '' '' '' '' '' '' '' '' '' '' '' '' '' ''' – jonrsharpe

+3

JSON сообщает вам, что значение '306' - это не тип, который он поддерживает *. Тот факт, что он имеет представление, что * выглядит * как целое число, явно вводит в заблуждение здесь, потому что, если он действительно был целым числом, вы бы не получили это исключение. Можете ли вы рассказать нам, что такое 'type (the_306_value)'? –

+1

@jonrsharpe @MartijnPieters Это 'numpy.int64', так что это и есть причина. Моя ошибка, спасибо! – zegkljan

ответ

3

Причина в том, что числа внутри dict не были обычным python int s, но numpy.in64 s, которые, по-видимому, не поддерживаются json encoder.

1

Как вы уже видели, типы данных NumPy Int64 не сериализации в JSON непосредственно:

>>> import numpy as np 
>>> import json 
>>> a=np.zeros(3, dtype=np.int64) 
>>> a[0]=-9223372036854775808 
>>> a[2]=9223372036854775807 
>>> jstr=json.dumps(a) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/local/Cellar/python3/3.4.1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/json/__init__.py", line 230, in dumps 
    return _default_encoder.encode(obj) 
    File "/usr/local/Cellar/python3/3.4.1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/json/encoder.py", line 192, in encode 
    chunks = self.iterencode(o, _one_shot=True) 
    File "/usr/local/Cellar/python3/3.4.1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/json/encoder.py", line 250, in iterencode 
    return _iterencode(o, 0) 
    File "/usr/local/Cellar/python3/3.4.1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/json/encoder.py", line 173, in default 
    raise TypeError(repr(o) + " is not JSON serializable") 
TypeError: array([-9223372036854775808,     0, 9223372036854775807]) is not JSON serializable 

Однако Python целые числа - в том числе более длинных целых чисел - можно сериализовать и десериализации:

>>> json.loads(json.dumps(2**123))==2**123 
True 

Итак, с помощью numpy вы можете напрямую преобразовывать данные в структуры данных Python, затем сериализуйте:

>>> jstr=json.dumps(a.tolist()) 
>>> b=np.array(json.loads(jstr)) 
>>> np.array_equal(a,b) 
True 
Смежные вопросы