Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preserve Python tuples with JSON

I'm still a little new to this, so I might not know all the conventional terms for things:

Is it possible to preserve Python tuples when encoding with JSON? Right now json.loads(json.dumps(tuple)) gives me a list back. I don't want to convert my tuples to lists, but I want to use JSON. So, are there options?

The reason why: I'm creating an app that uses multi-dimensional arrays, not always the same shape. I've got some class methods that use recursion to probe the arrays and cast the endpoints as a string or int. I recently realized that (based on how my recursion works) I can use tuples to prevent deeper recursive searching of arrays (Python rawks). This could come in handy in situations where I know I for sure I won't need to be probing any deeper into my data structures.

like image 580
mrKelley Avatar asked Mar 30 '13 17:03

mrKelley


People also ask

Are tuples JSON serializable Python?

Python tuples are JSON serializable, just like lists or dictionaries. The JSONEncoder class supports the following objects and types by default. The process of converting a tuple (or any other native Python object) to a JSON string is called serialization.

How do I save a JSON file in Python?

Saving a JSON File We do need to import the json library and open the file. To actually write the data to the file, we just call the dump() function, giving it our data dictionary and the file object.


2 Answers

You can write a highly-specialzed encoder and a decoder hook:

import json  class MultiDimensionalArrayEncoder(json.JSONEncoder):     def encode(self, obj):         def hint_tuples(item):             if isinstance(item, tuple):                 return {'__tuple__': True, 'items': item}             if isinstance(item, list):                 return [hint_tuples(e) for e in item]             if isinstance(item, dict):                 return {key: hint_tuples(value) for key, value in item.items()}             else:                 return item          return super(MultiDimensionalArrayEncoder, self).encode(hint_tuples(obj))  def hinted_tuple_hook(obj):     if '__tuple__' in obj:         return tuple(obj['items'])     else:         return obj   enc = MultiDimensionalArrayEncoder() jsonstring =  enc.encode([1, 2, (3, 4), [5, 6, (7, 8)]])  print jsonstring  # [1, 2, {"items": [3, 4], "__tuple__": true}, [5, 6, {"items": [7, 8], "__tuple__": true}]]  print json.loads(jsonstring, object_hook=hinted_tuple_hook)  # [1, 2, (3, 4), [5, 6, (7, 8)]] 
like image 106
Pavel Anossov Avatar answered Oct 05 '22 09:10

Pavel Anossov


Nope, it's not possible. There is no concept of a tuple in the JSON format (see here for a concise breakdown of what types exist in JSON). Python's json module converts Python tuples to JSON lists because that's the closest thing in JSON to a tuple.

You haven't given much detail of your use case here, but if you need to store string representations of data structures that include tuples, a few possibilities immediately come to mind, which may or may not be appropriate depending upon your situation:

  1. Create your own encoding and decoding functions
  2. Use pickle (careful; pickle.loads isn't safe to use on user-provided input).
  3. Use repr and ast.literal_eval instead of json.dumps and json.loads. repr will give you output reasonably similar in appearance to json.dumps, but repr will not convert tuples to lists. ast.literal_eval is a less powerful, more secure version of eval which will only decode strings, numbers, tuples, lists, dicts, booleans, and None.

Option 3 is probably the easiest and simplest solution for you.

like image 40
Mark Amery Avatar answered Oct 05 '22 10:10

Mark Amery