无法将numpy数组转换为JSON

时间:2016-04-05 19:10:03

标签: python json python-3.x numpy

我正在尝试编写一个JSONEncoder,因此我可以将一些Python对象数据转储到JSON文本,以便由另一个应用程序读取。我在转换numpy数组时遇到了特别的麻烦。我已经阅读了很多关于这个主题的SO文章,我在本文SimpleJSON and NumPy array中大量借用了@tlausch的解决方案 - 但是我无法让它发挥作用。

我有一个非常简单的课程来演示我的问题:

import numpy as np
class Movement:
    def __init__(self, t1,t2,t3,t4):
        self._t1 = t1
        self._t2 = t2
        self._t3 = t3
        self._t4 = t4
        self._a0 = np.array([0,0,0])

以下是我的JSONEncoder的代码:

import json
import base64
import numpy as np
class MovementEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray):
            if obj.flags['C_CONTIGUOUS']:
                obj_data = obj.data
            else:
                cont_obj = np.ascontiguousarray(obj)
                assert(cont_obj.flags['C_CONTIGUOUS'])
                obj_data = cont_obj.data
            data_b64 = base64.b64encode(obj_data)
            return dict(__ndarray__ = data_b64, dtype = str(obj.dtype), shape = obj.shape)
        try:
            my_dict = obj.__dict__   ## <-- ERROR raised here
        except TypeError:
            pass
        else:
            return my_dict
        return json.JSONEncoder.default(self, obj)

当我创建一个简单的Movement对象,然后调用encoder.encode(obj)时,我收到以下错误:

>>> obj = Movement(1,2,3,4)
>>> encoder = MovementEncoder()
>>> encoder.encode(obj)
...
    'bytes' object has no attribute '__dict__'

通过向编码器添加一些打印语句,我可以看到它正确地从对象,对象的字典,再到具有np.array类型的属性递归。我认为这个解决方案的重点是默认情况下ndarray类型的base64表示形式是JSON可编码的,但似乎并非如此。我哪里出错了?

注意:使用Python 3.4和NumPy 1.8.2

编辑:更新代码以显示错误发生的位置

1 个答案:

答案 0 :(得分:1)

我终于能够通过调整numpy ndarray类型的返回值来返回列表而不是dict来解决这个问题。我使用了numpy内置方法tolist(),该方法返回一个ndarray的json可编码表示。

import json
import base64
import numpy as np
class MovementEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray):
            if obj.flags['C_CONTIGUOUS']:
                obj_data = obj.data
            else:
                cont_obj = np.ascontiguousarray(obj)
                assert(cont_obj.flags['C_CONTIGUOUS'])
                obj_data = cont_obj.data
            ## data_b64 = base64.b64encode(obj_data)
            ## converting to base64 and returning a dictionary did not work
            ## return dict(__ndarray__ = data_b64, dtype = str(obj.dtype), shape = obj.shape)
            return obj.tolist()  ## instead, utilize numpy builtin tolist() method
        try:
            my_dict = obj.__dict__   ## <-- ERROR raised here
        except TypeError:
            pass
        else:
            return my_dict
        return json.JSONEncoder.default(self, obj)