2

I am trying to write a JSONEncoder so I can dump some of my Python object data to JSON text to be read in by another application. I am having particular trouble converting the numpy arrays. I have read many of the SO articles on the subject, and I have borrowed heavily from @tlausch's solution in this article SimpleJSON and NumPy array - but I have not been able to get it working.

I have a pretty simple class that demonstrates my problem:

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

Here is the code from my 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)

When I create a simple Movement object, and then call encoder.encode(obj), I get the following error:

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

By adding some print statements to the encoder, I can see that it is correctly recursing from the object, to the object's dictionary, then to the attribute that has the np.array type. I thought the point of this solution was that the base64 representation of the ndarray type was JSON encodable by default, but that appears not to be the case. Where did I go wrong?

Note: using Python 3.4, and NumPy 1.8.2

EDIT: updated code to show where error occurs

asked Apr 5, 2016 at 19:10
7
  • Your code runs successfully for me on python 2.7.5 with numpy 1.7.1 Commented Apr 5, 2016 at 19:53
  • Oh, forgot to specify python 3.4 and numpy 1.8.2... Commented Apr 5, 2016 at 19:55
  • Based on the full traceback, which line is throwing that error? Commented Apr 5, 2016 at 20:25
  • @AlexHall Updated Question to point to where error occurs Commented Apr 5, 2016 at 20:35
  • Why not catch AttributeError instead of TypeError? Commented Apr 5, 2016 at 20:38

1 Answer 1

3

I was finally able to solve this problem by adjusting the return value for numpy ndarray types to return a list, instead of a dict. I used the numpy builtin method tolist(), which returns a json-encodable representation of an ndarray.

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)
answered Apr 22, 2016 at 19:20
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.