Подтвердить что ты не робот

Сохранять кортежи Python с JSON

Я все еще немного новичок в этом, поэтому я мог бы не знать всех обычных терминов для вещей:

Можно ли сохранять кортежи Python при кодировании с помощью JSON? Прямо сейчас json.loads(json.dumps(tuple)) возвращает мне список. Я не хочу преобразовывать свои кортежи в списки, но я хочу использовать JSON. Итак, есть ли варианты?

Причина: Я создаю приложение, которое использует многомерные массивы, не всегда одинаковой формы. У меня есть методы класса, которые используют рекурсию для проверки массивов и перевода конечных точек в виде строки или int. Недавно я понял, что (на основе того, как работает моя рекурсия) я могу использовать кортежи для предотвращения более глубокого рекурсивного поиска массивов (Python rawks). Это может пригодиться в ситуациях, когда я знаю, что я уверен, что мне не нужно будет углубляться в мои структуры данных.

4b9b3361

Ответ 1

Вы можете написать высокоспециализированный кодер и хук декодера:

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

Ответ 2

Нет, это невозможно. В формате JSON нет понятия кортежа (см. здесь для краткого разбиения того, какие типы существуют в JSON). Модуль Python json преобразует кортежи Python в списки JSON, потому что это самое близкое в JSON к кортежу.

Здесь вы не указали подробные сведения о своем прецеденте, но если вам нужно хранить строковые представления структур данных, содержащих кортежи, сразу приходят в голову несколько возможностей, которые могут быть или не быть подходящими в зависимости от вашей ситуации

  • Создайте собственные функции кодирования и декодирования.
  • Используйте pickle (осторожно; pickle.loads небезопасно использовать для ввода пользователем).
  • Используйте repr и ast.literal_eval вместо от json.dumps и json.loads. repr даст вам результат, похожий по внешнему виду, на json.dumps, но repr не преобразует кортежи в списки. ast.literal_eval - менее мощная, более безопасная версия eval, которая будет расшифровывать только строки, числа, кортежи, списки, dicts, booleans, и None.

Вариант 3 - это, пожалуй, самое простое и простое решение для вас.

Ответ 3

Это с simplejson

import simplejson

def _to_json(python_object) :
    if isinstance(python_object, tuple) :
        python_object = {'__class__': 'tuple',
                         '__value__': list(python_object)}
    else :
        raise TypeError(repr(python_object) + ' is not JSON serializable') 

    return python_object

def _from_json(json_object):                                   
    if json_object['__class__'] == 'tuple':
        return tuple(json_object['__value__'])
    return json_object


jsn = simplejson.dumps((1,2,3), 
                       default=_to_json, 
                       tuple_as_array=False)

tpl = simplejson.loads(jsn, object_hook=_from_json)

Ответ 4

Принципиальным отличием списков Python от кортежей является изменчивость, которая не имеет отношения к представлениям JSON, если вы не планируете изменять внутренние члены списка JSON, пока он находится в текстовой форме. Вы можете просто превратить списки, которые вы получаете обратно в кортежи. Если вы не используете какие-либо пользовательские декодеры объектов, единственными структурированными типами данных, которые вы должны учитывать, являются объекты и массивы JSON, которые выдаются как команды и списки Python.

def tuplify(listything):
    if isinstance(listything, list): return tuple(map(tuplify, listything))
    if isinstance(listything, dict): return {k:tuplify(v) for k,v in listything.items()}
    return listything

Если вы специализируетесь на декодировании или хотите, чтобы некоторые массивы JSON были списками Python, а другие - кортежами Python, вам нужно будет обернуть элементы данных в dict или кортеж, который аннотирует информацию о типе. Само по себе это лучший способ влиять на поток управления алгоритма, чем ветвление, основанное на том, является ли что-то списком или кортежем (или другим итеративным типом).