使用JSON保存Python元组

dddzy1tm  于 5个月前  发布在  Python
关注(0)|答案(6)|浏览(90)

我对这个还有点陌生,所以我可能不知道所有的传统术语:
在使用JSON编码时,是否可以保留Python元组?现在json.loads(json.dumps(tuple))给了我一个列表。我不想将元组转换为列表,但我想使用JSON。那么,有选择吗?
原因是:我正在创建一个应用程序,它使用多维数组,并不总是相同的形状。我有一些类方法,使用递归来探测数组并将端点转换为字符串或int。我最近意识到,(基于我的递归的工作方式)我可以使用元组来防止数组的更深层次的递归搜索(Python rawks)。在我确定不需要更深入地探究数据结构的情况下,这可能会派上用场。

bkhjykvo

bkhjykvo1#

你可以编写一个高度专业化的编码器和解码器钩子:

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

字符串

gcuhipw9

gcuhipw92#

不,这是不可能的。JSON格式中没有元组的概念(参见这里对JSON中存在的类型的简要分类)。Python的json模块将Python元组转换为JSON列表,因为这是JSON中最接近元组的东西。
您在这里没有详细介绍您的用例,但是如果您需要存储包含元组的数据结构的字符串表示,那么您会立即想到一些可能性,这些可能性可能适合,也可能不适合,具体取决于您的情况:
1.创建您自己的编码和解码函数
1.使用pickle(请注意,在用户提供的输入上使用pickle.loads是不安全的)。
1.使用reprast.literal_eval代替json.dumpsjson.loadsrepr的输出在外观上与json.dumps相当相似,但repr不会将元组转换为列表。ast.literal_evaleval的一个功能较弱但更安全的版本,它只会解码字符串、数字、元组、列表、字典、布尔值,和None的组合。
选项3可能是最简单的解决方案。

s3fp2yjn

s3fp2yjn3#

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元组,你需要将数据项 Package 在一个标注类型信息的dict或tuple中。这本身是一种更好的方式来影响算法的控制流,而不是根据某个东西是列表还是元组(或其他可迭代类型)进行分支。

m1m5dgzv

m1m5dgzv4#

这是与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)

字符串

nkcskrwz

nkcskrwz5#

Pavel Anossov很好地回答了这个问题。为了对元组之类的对象进行编码,代码可以工作。将元组作为Python的dict键也很有用,上面的代码并没有将元组作为dict键来处理。为了将元组作为键来管理,可以使用一个布尔标志来表示元组是否是一个dict键,并且元组被 Package 在json.dumps(...)输出层中;在解码过程中,json通过递归来处理。
解决方案可以允许传递元组与值的数据结构,从而实现更容易的哈希。Python def __hash__(self):经常返回对象中项目元组的哈希,有时使用不 Package 在类中的更简单的数据结构是有用的。

  1. hint_tuples可以有一个命名参数dict_key --tuple是一个dict键的标志。Python的dict type不能是dict的键,最好用json.dumps(...)把它转换成一个字符串,在解码过程中,这应该被恢复为dict,递归应该注意它被转换成tuple。
    1.可选地,X1 m1n1x可以被混淆,使得在某人将字符串X1 m2n1x编码为Dict密钥的一部分的情况下,它可以通过编码器/解码器。
    下面的代码是我用来处理Python字典键中的元组编码的代码。__main__中包含了一些基本的测试来演示解决方案。为了增加通过解决方案的案例数量,放弃了编码输出的可读性。
# Pavel Anossov's solution hinted this:
    
    import json
    tuple_signifier = '__tuple__s_i_g_n_i_f_i_e_r__'
    
    class StreamTuple(dict):
         def __hash__(self):
             return hash(str(self))
    
    class MultiDimensionalArrayEncoder(json.JSONEncoder):
        def encode(self, obj):
            def hint_tuples(item, dict_key=False):
                global tuple_signifier
                ret_val = None
                if isinstance(item, tuple):
                    if dict_key:
                        ret_val = json.dumps(dict(
                            [(
                                tuple_signifier,
                                json.dumps(hint_tuples(list(item))),
                            ),],
                        ))
                    else:
                        ret_val = dict(
                            [(
                                tuple_signifier,
                                json.dumps(hint_tuples(list(item))),
                            ),],
                        )
    
                elif isinstance(item, list):
                    ret_val = [hint_tuples(e) for e in item]
                elif isinstance(item, dict):
                    ret_val = dict([
                        (hint_tuples(key, dict_key=True), hint_tuples(value))
                        for key, value in item.items()
                    ])
                else:
                    ret_val = item
                return ret_val
            return super(MultiDimensionalArrayEncoder, self).\
                         encode(hint_tuples(obj))
    
    
    def hinted_tuple_hook(obj):
        global tuple_signifier
    
        ret_val = {}
        if tuple_signifier in obj:
            ret_val = tuple(json.loads(obj[tuple_signifier], object_hook=hinted_tuple_hook,))
        else:
            for k, v in obj.items():
                inner_k = k
                inner_v = v
                if isinstance(k, str) and tuple_signifier in k:
                    inner_k = json.loads(k, object_hook=hinted_tuple_hook,)
                if isinstance(v, str) and tuple_signifier in v:
                    inner_v = json.loads(v, object_hook=hinted_tuple_hook,)
                ret_val[inner_k] = inner_v
        return ret_val
    
    #
    # Some tests that show how to use the above hinted tuple hook to encode 
    # / decode Python tuples.
    #
    if __name__ == '__main__':
        enc = MultiDimensionalArrayEncoder()
        test_input_1 = (2,)
        test_input_2 = {(2,): 'a'}
        test_input_3 = {'a': {(2,): {1:'a'}}}
        print('test_input_1 encoded:', enc.encode(test_input_1), test_input_1)
        print('test_input_1 decoded:',
            json.loads(enc.encode(test_input_1),
                object_hook=hinted_tuple_hook,)
        )
    #"""
        print('test_input_2 encoded:', enc.encode(test_input_2))
        print('test_input_2 decoded:',
            json.loads(enc.encode(test_input_2),
                object_hook=hinted_tuple_hook,)
        )
    
        print('\n' * 3)
        print('test_input_3 encoded:', enc.encode(test_input_3))
        print('test_input_3 decoded:',
            json.loads(enc.encode(test_input_3),
                object_hook=hinted_tuple_hook,)
        )
    
        print('\n' * 3)
        test_input_4 = {'a': 'b'}
        print('test_input_4  encoded:', enc.encode(test_input_4))
        print('test_input_4 decoded:',
            json.loads(enc.encode(test_input_4),
                object_hook=hinted_tuple_hook,)
        )
    
        #"""

字符串

yrdbyhpb

yrdbyhpb6#

这个例子怎么样:

import json

def serialize(obj):
    if isinstance(obj, tuple):
        return {'__tuple__': True, 'items': list(obj)}
    elif isinstance(obj, list):
        return [serialize(item) for item in obj]
    elif isinstance(obj, dict):
        return {key: serialize(value) for key, value in obj.items()}
    else:
        return obj

def deserialize(obj):
    if isinstance(obj, list):
        return [deserialize(item) for item in obj]
    elif isinstance(obj, dict):
        if '__tuple__' in obj:
            return tuple(obj['items'])
        else:
            return {key: deserialize(value) for key, value in obj.items()}
    else:
        return obj

original_dict = {'tuple_key': [(1, 2, 3), 4], 'nested': {'key': (5, 6, 7)}}

json_data = json.dumps(serialize(original_dict))

decoded_dict = deserialize(json.loads(json_data))

# Print the results

个字符

相关问题