我有一些非常简单的代码,它接受一个将元组作为键的字典,并将其转换为json格式:
In [11]:
import simplejson as json
In [12]:
data = {('category1', 'category2'): 4}
In [13]:
json.dumps(data)
然而运行代码后,我得到了:
TypeError: keys must be a string
我已经尝试使用 str() 函数将键和其他所有找到的东西转换为字符串,但都没有成功。
我有一些非常简单的代码,它接受一个将元组作为键的字典,并将其转换为json格式:
In [11]:
import simplejson as json
In [12]:
data = {('category1', 'category2'): 4}
In [13]:
json.dumps(data)
然而运行代码后,我得到了:
TypeError: keys must be a string
我已经尝试使用 str() 函数将键和其他所有找到的东西转换为字符串,但都没有成功。
str()
类型:>>> data = {str(('category1', 'category2')): 4}
它完全正常运作:
>>> json.dumps(data)
'{"(\'category1\', \'category2\')": 4}'
话虽如此,在您的位置上,我会考虑让您的密钥更易读。可能是这样的:
>>> data = dict((':'.join(k), v) for k,v in data.items())
这将把一个键值对如 ('category1', 'category2')
转换为 category1:category2
,
json
序列化是一个双向操作...仅执行dumps
是不够的,还需要知道如何执行loads
。 - Dr_Zaszuśloads
即可完成。如果数据结构需要元组作为键,则解决方案将会有所不同。话虽如此,如果您对反序列化JSON有特定的问题,请随时提出新问题,我们很乐意帮助您。 - larsks但是,在我的情境中,我有一些嵌套字典。因此,我对其进行了递归处理:扁平优于嵌套。
import json
def key_to_json(data):
if data is None or isinstance(data, (bool, int, str)):
return data
if isinstance(data, (tuple, frozenset)):
return str(data)
raise TypeError
def to_json(data):
if data is None or isinstance(data, (bool, int, tuple, range, str, list)):
return data
if isinstance(data, (set, frozenset)):
return sorted(data)
if isinstance(data, dict):
return {key_to_json(key): to_json(data[key]) for key in data}
raise TypeError
data = {('category1', 'category2'): {frozenset(['cat1', 'cat2']): 1212}}
json.dumps(to_json(data))
# '{"(\'category1\', \'category2\')": {"frozenset({\'cat2\', \'cat1\'})": 1212}}'
调整此代码以适应您的上下文。
data =['category1', 'category2']
data_map = {}
data_map[','.join(data)]= 4
json.dumps(data_map)
stringify
方法:import json
import numpy as np
from collections.abc import Iterable
encode = json.JSONEncoder().encode
def cast_key(key):
"Cast dictionary key"
try:
encode({key: 123})
return key
except:
pass
if isinstance(key, tuple):
return encode(key)
return str(key)
def cast_value(value):
"Cast dictionary value"
try:
encode(value)
return value
except TypeError:
pass
try:
if np.issubdtype(value, np.integer):
return int(value)
except ValueError:
pass
return str(value)
def coerce_types(arg):
if isinstance(arg, dict):
obj = {}
for k, v in arg.items():
k = cast_key(k)
if isinstance(v, dict):
v = coerce_types(v)
else:
v = cast_value(v)
obj[k] = v
return obj
elif isinstance(arg, Iterable):
return [coerce_types(e) for e in arg]
else:
return cast_value(arg)
def stringify(obj):
# First try default serializer
try:
return json.dumps(obj)
except TypeError:
pass
# Default failed, so we coerce types and try again
obj_prep = coerce_types(obj)
return json.dumps(obj_prep)
import numpy as np
from stringify import stringify
def test_simple_object():
input = {'foo': 'bar'}
expected = '{"foo": "bar"}'
actual = stringify(input)
assert expected == actual
def test_nested_object():
input = {'foo': {'child': 'bar'}, 'age': 20}
expected = '{"foo": {"child": "bar"}, "age": 20}'
actual = stringify(input)
assert expected == actual
def test_numpy_value_int():
input = {'foo': np.int64(123)}
expected = '{"foo": 123}'
actual = stringify(input)
assert expected == actual
def test_numpy_value_float():
input = {'foo': np.float64(123.456)}
expected = '{"foo": 123.456}'
actual = stringify(input)
assert expected == actual
def test_numpy_key():
input = {np.int64(123): 'foo'}
expected = '{"123": "foo"}'
actual = stringify(input)
assert expected == actual
def test_numpy_nested_l1():
input = {'foo': {'bar': {np.int64(123): 'foo'}}, 'age': 20}
expected = '{"foo": {"bar": {"123": "foo"}}, "age": 20}'
actual = stringify(input)
assert expected == actual
def test_numpy_nested_l2():
input = {'foo': {'bar': {'baz': {'foo': np.int64(123)}}}, 'age': 20}
expected = '{"foo": {"bar": {"baz": {"foo": 123}}}, "age": 20}'
actual = stringify(input)
assert expected == actual
def test_array_int():
input = [1, 2, 3]
expected = '[1, 2, 3]'
actual = stringify(input)
assert expected == actual
def test_array_numpy_int():
input = [np.int64(n) for n in [1, 2, 3]]
expected = '[1, 2, 3]'
actual = stringify(input)
assert expected == actual
def test_array_numpy_float():
input = [np.float64(n) for n in [1.1, 2.2, 3.3]]
expected = '[1.1, 2.2, 3.3]'
actual = stringify(input)
assert expected == actual
def test_object_array():
input = [{'foo': 'bar'}]
expected = '[{"foo": "bar"}]'
actual = stringify(input)
assert expected == actual
def test_object_array_numpy():
input = [{'foo': 'bar'}, {'bar': np.int64(123)}]
expected = '[{"foo": "bar"}, {"bar": 123}]'
actual = stringify(input)
assert expected == actual
def test_tuple_value():
input = {'foo': ('bar', 'baz')}
expected = '{"foo": ["bar", "baz"]}'
actual = stringify(input)
assert expected == actual
def test_tuple_key():
input = {('bar', 'baz'): 'foo'}
expected = '{"[\\"bar\\", \\"baz\\"]": "foo"}'
actual = stringify(input)
assert expected == actual
如果您的目的是“保存”,只需使用pickle。
API几乎相同。
import pickle
data = {('category1', 'category2'): 4}
s = pickle.dumps(data) # serialized data
d = pickle.loads(s) # the original dictionary
# write
with open('file1.pkl', 'wb') as f:
pickle.dump(data, f)
# read
with open('file1.pkl', 'rb') as f:
data = pickle.load(f)
('category1', 'category2')
的键,实际上,它根本不支持元组。因此,你需要重新组织你的数据。 - user2357112