使用 JSON 保留 Python 元组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15721363/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Preserve Python tuples with JSON
提问by mrKelley
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?
使用 JSON 编码时是否可以保留 Python 元组?现在json.loads(json.dumps(tuple))给我一个清单。我不想将元组转换为列表,但我想使用 JSON。那么,有选择吗?
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.
原因:我正在创建一个使用多维数组的应用程序,而不总是相同的形状。我有一些使用递归来探测数组并将端点转换为字符串或整数的类方法。我最近意识到(基于我的递归工作方式)我可以使用元组来防止更深层次的数组递归搜索(Python rawks)。在我知道我肯定不需要深入研究我的数据结构的情况下,这可能会派上用场。
采纳答案by Pavel Anossov
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)]]
回答by Mark Amery
Nope, it's not possible. There is no concept of a tuple in the JSON format (see herefor a concise breakdown of what types exist in JSON). Python's jsonmodule converts Python tuples to JSON lists because that's the closest thing in JSON to a tuple.
不,这是不可能的。JSON 格式中没有元组的概念(有关 JSON 中存在哪些类型的简要分类,请参见此处)。Python 的json模块将 Python 元组转换为 JSON 列表,因为这是 JSON 中最接近元组的东西。
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:
您在此处没有详细说明您的用例,但是如果您需要存储包含元组的数据结构的字符串表示形式,则会立即想到一些可能性,这可能适合也可能不适合,具体取决于您的情况:
- Create your own encoding and decoding functions
- Use pickle(careful;
pickle.loadsisn't safe to use on user-provided input). - Use
reprandast.literal_evalinstead ofjson.dumpsandjson.loads.reprwill give you output reasonably similar in appearance tojson.dumps, butreprwill not convert tuples to lists.ast.literal_evalis a less powerful, more secure version ofevalwhich will only decode strings, numbers, tuples, lists, dicts, booleans, andNone.
- 创建自己的编码和解码功能
- 使用pickle(小心;
pickle.loads在用户提供的输入上使用不安全)。 - 使用
reprandast.literal_eval代替json.dumpsandjson.loads。repr将为您提供外观上与 相当相似的输出json.dumps,但repr不会将元组转换为列表。ast.literal_eval是一个功能较弱、更安全的版本,eval它只会解码字符串、数字、元组、列表、字典、布尔值和None.
Option 3 is probably the easiest and simplest solution for you.
选项 3 对您来说可能是最简单、最简单的解决方案。
回答by rhoark
The principal difference between python lists and tuples is mutability, which is irrelevant to JSON representations, as long as you're not contemplating modifying the internal members of the JSON list while it's in text form. You can just turn the lists you get back into tuples. If you're not using any custom object decoders, the only structured datatypes you have to consider are JSON objects and arrays, which come out as python dicts and lists.
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
If you are specializing the decoding, or want some JSON arrays to be python lists and others to be python tuples, you'll need to wrap data items in a dict or tuple that annotates type information. This in itself is a better way to influence an algorithm's control flow than branching based on whether something is a list or tuple (or some other iterable type).
如果您专门进行解码,或者希望某些 JSON 数组是 python 列表而其他数组是 python 元组,则需要将数据项包装在注释类型信息的 dict 或元组中。这本身是一种影响算法控制流的更好方法,而不是基于某些内容是列表还是元组(或其他可迭代类型)进行分支。
回答by fgregg
It is with simplejson
用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)

