使用自定义编码将带十进制键的python字典转换为JSON

2024-04-27 11:24:26 发布

您现在位置:Python中文网/ 问答频道 /正文

JSON只允许字符串作为键。在

下面的代码使用自定义JSONEncoder将Decimal值转换为字符串。在

有没有一种方法可以指定一个将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。在

注意:显然,我可以遍历我的字典,用字符串值替换Decimal类型,但是我希望找到一个更优雅的解决方案,也许可以通过在编码器中添加行为来实现。在


Tags: 字符串importselfjsonobjdefaultreturn编码器
1条回答
网友
1楼 · 发布于 2024-04-27 11:24:26

不,你不能钩住键的处理,你必须在编码之前转换它们。您可以使用如下递归处理程序来执行此操作:

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时使用:

^{pr2}$

您也可以通过添加另一个注册表来扩展它来处理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]

演示:

>>> string_keys([{Decimal(0): 'foo'}])
[{'0': 'foo'}]
>>> keys_to_decimal(string_keys([{Decimal(0): 'foo'}]))
[{Decimal('0'): 'foo'}]

相关问题 更多 >