我正在尝试编写一个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
编辑:更新代码以显示错误发生的位置
答案 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)