Encoding Python Enum to JSON
我有一个字典,其中一些键是枚举实例(enum.enum的子类)。我正试图使用文档中的自定义JSON编码器类将字典编码为JSON字符串。我只想让输出的JSON中的键是枚举名称的字符串。例如,
我编写了一个简单的测试用例,如下所示,我在干净的virtualenv中进行了测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | import json from enum import Enum class TestEnum(Enum): one ="first" two ="second" three ="third" class TestEncoder(json.JSONEncoder): """ Custom encoder class""" def default(self, obj): print("Default method called!") if isinstance(obj, TestEnum): print("Seen TestEnum!") return obj.name return json.JSONEncoder.default(self, obj) def encode_enum(obj): """ Custom encoder method""" if isinstance(obj, TestEnum): return obj.name else: raise TypeError("Don't know how to decode this") if __name__ =="__main__": test = {TestEnum.one :"This", TestEnum.two :"should", TestEnum.three :"work!"} # Test dumps with Encoder method #print("Test with encoder method:") #result = json.dumps(test, default=encode_enum) #print(result) # Test dumps with Encoder Class print("Test with encoder class:") result = json.dumps(test, cls=TestEncoder) print(result) |
我无法成功地对字典进行编码(使用python 3.6.1)。我不断地得到
我见过涉及intenum类的解决方案,但我需要枚举的值是字符串。我还看到了这个答案,它讨论了一个与从另一个类继承的枚举相关的问题。但是,我的枚举只从基枚举继承。枚举类并正确响应
当提供给
1 2 3 4 5 6 7 8 9 10 11 12 13 | $ python3 enum_test.py Test with encoder class Traceback (most recent call last): File"enum_test.py", line 59, in <module> result = json.dumps(test, cls=TestEncoder) File"/usr/lib64/python3.6/json/__init__.py", line 238, in dumps **kw).encode(obj) File"/usr/lib64/python3.6/json/encoder.py", line 199, in encode chunks = self.iterencode(o, _one_shot=True) File"/usr/lib64/python3.6/json/encoder.py", line 257, in iterencode return _iterencode(o, 0) TypeError: keys must be a string |
号
我假设问题是jsonEncoder类的
任何帮助都将不胜感激!
在要转换为JSON的字典中,除了字符串之外,不能使用任何东西作为键。编码器没有提供任何其他选项;只对未知类型的值调用
将密钥转换为前面的字符串:
1 2 3 4 5 6 7 8 | def convert_keys(obj, convert=str): if isinstance(obj, list): return [convert_keys(i, convert) for i in obj] if not isinstance(obj, dict): return obj return {convert(k): convert_keys(v, convert) for k, v in obj.items()} json.dumps(convert_keys(test)) |
这将递归地处理字典键。注意,我包含了一个钩子;然后您可以选择如何将枚举值转换为字符串:
1 2 3 4 5 6 | def enum_names(key): if isinstance(key, TestEnum): return key.name return str(key) json.dumps(convert_keys(test, enum_names)) |
号
从JSON加载时,可以使用相同的函数来反转过程:
1 2 3 4 5 6 7 | def names_to_enum(key): try: return TestEnum[key] except KeyError: return key convert_keys(json.loads(json_data), names_to_enum) |
演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | >>> def enum_names(key): ... if isinstance(key, TestEnum): ... return key.name ... return str(key) ... >>> json_data = json.dumps(convert_keys(test, enum_names)) >>> json_data '{"one":"This","two":"should","three":"work!"}' >>> def names_to_enum(key): ... try: ... return TestEnum[key] ... except KeyError: ... return key ... >>> convert_keys(json.loads(json_data), names_to_enum) {<TestEnum.one: 'first'>: 'This', <TestEnum.two: 'second'>: 'should', <TestEnum.three: 'third'>: 'work!'} |
。