使用自定义编码器将带十进制键的python字典转换为JSON
JSON只允许字符串作为键 下面的代码使用自定义JSONECODER将使用自定义编码器将带十进制键的python字典转换为JSON,python,json,python-3.x,decimal,Python,Json,Python 3.x,Decimal,JSON只允许字符串作为键 下面的代码使用自定义JSONECODER将Decimal值转换为字符串 有没有一种方法可以指定将十进制键转换为字符串的编码器 import json import decimal class DecimalEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, decimal.Decimal): return str(obj)
Decimal
值转换为字符串
有没有一种方法可以指定将十进制
键转换为字符串的编码器
import json
import decimal
class DecimalEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, decimal.Decimal):
return str(obj)
return json.JSONEncoder.default(self, obj)
d1 = {3: decimal.Decimal(50)}
print(json.dumps(d1, cls=DecimalEncoder))
d2 = {decimal.Decimal(50): 3}
json.dumps(d2, cls=DecimalEncoder) # TypeError: keys must be a string
我正在使用python3.6
注意:显然,我可以遍历我的字典并用字符串值替换十进制类型,但我希望通过向编码器添加行为来找到一个更优雅的解决方案。不,你不能钩住键的处理,你必须在编码之前转换它们。可以使用递归处理程序执行此操作,如:
from functools import singledispatch
@singledispatch
def string_keys(obj):
return obj
@string_keys.register(dict)
def _(d):
return {str(k): string_keys(v) for k, v in d.items()}
@string_keys.register(list)
def _(l):
return [string_keys(v) for v in l]
所有这些都是递归地转换列表和dict的嵌套结构,其中所有键都被强制为字符串
转换为JSON时使用此选项:
json_encoded = json.dumps(string_keys(data))
通过添加另一个注册表,您也可以将其扩展为处理Decimal
对象(键之外):
@string_keys.register(Decimal)
def _(d):
return str(d)
换一种方式是有点棘手的,除非您显式地标记Decimal
键(比如使用前缀),否则您无法轻松区分以字符串开头的键和Decimal
值。您可以在此处使用try/except
方法:
from functools import singledispatch
@singledispatch
def keys_to_decimal(obj):
return obj
@keys_to_decimal.register(dict)
def _(d):
def try_decimal(k):
try:
return Decimal(k)
except ValueError:
return k
return {try_decimal(k): keys_to_decimal(v) for k, v in d.items()}
@keys_to_decimal.register(list)
def _(l):
return [keys_to_decimal(v) for v in l]
演示:
我得到了这个错误
NameError:name'k'没有在return{str(k):string_keys(v)for v in d}
@ChrisGuest:这是keys_to_decimal
处理中的另一个错误;现在已实际测试。:-)
>>> string_keys([{Decimal(0): 'foo'}])
[{'0': 'foo'}]
>>> keys_to_decimal(string_keys([{Decimal(0): 'foo'}]))
[{Decimal('0'): 'foo'}]