来自json.dumps的奇怪的TypeError

时间:2014-09-15 14:00:17

标签: python json python-3.x numpy dictionary

在python 3.4.0中,使用json.dumps()在一个案例中抛出了一个TypeError,但在其他情况下就像魅力一样(我认为它等同于第一个)。

我有一个字典,其中键是字符串,值是数字和其他字符串(即类似{'x': 1.234, 'y': -5.678, 'z': {'a': 4, 'b': 0, 'c': -6}})。

这失败了(堆栈跟踪不是来自这个特定的代码片段,而是来自我的大脚本,我不会在这里粘贴,但它本质上是相同的):

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

306x中其中一个内部词汇中的值之一。它并不总是相同的数字,有时它是字典中包含的不同数字,显然是因为字典的无序性。

然而,这就像一个魅力:

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

请有人告诉我为什么会发生这种情况或可能是什么原因?最令人困惑的部分是这两个词组(原始词和通过评估原始词的表示获得的词)是相同的,但dumps()函数对每个词的行为都不同。

2 个答案:

答案 0 :(得分:3)

原因是dict内的数字不是普通的python int,而是numpy.in64,而json编码器显然不支持这些数字。

答案 1 :(得分: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