Python Enum存储自定义对象时pickle反序列化失败如何解决
问题根因
报错和SiteInformation的__init__方法无关,核心是Python Enum的序列化机制和自定义类默认相等规则的冲突:
- pickle序列化Enum成员时,默认不会存储成员本身,只会存储成员绑定的value值;反序列化时会用恢复出来的value作为参数调用枚举类,查找匹配的成员返回
- 自定义类
SiteInformation默认继承自object的__eq__方法是按对象内存地址判断相等:反序列化生成的SiteInformation是全新实例,和枚举定义时绑定在Site.GN、Site.GS上的原始实例内存地址不同,相等判断结果为False - 枚举类遍历所有成员都找不到和传入value匹配的项,就会抛出
ValueError: xxx is not a valid Site错误。
你之前加__repr__方法只能优化报错输出,没有解决实例不相等的核心问题,自然无法修复报错。
解决方案
以下两种方案都可以彻底解决问题,按需选择即可:
方案1:给SiteInformation增加值相等判断逻辑
改动最小,只要让属性一致的SiteInformation实例能被判定为相等,枚举类就能自动匹配到正确成员:
class SiteInformation: def __init__(self, name, location): self.name = name self.location = location # 实际业务中的计算逻辑 self.time_zone = 'UTC' def __eq__(self, other): if not isinstance(other, SiteInformation): return NotImplemented # 按需选择能唯一标识站点的属性做相等判断即可 return (self.name == other.name and self.location == other.location and self.time_zone == other.time_zone) # 自定义__eq__后必须同步实现__hash__,保证实例可正常作为字典key、枚举值使用 def __hash__(self): return hash((self.name, self.location, self.time_zone))
添加上述两个方法后,原代码不需要做其他修改即可正常序列化、反序列化。
方案2:自定义枚举类的序列化规则
如果不想修改SiteInformation类的逻辑,可以直接给枚举类定义__reduce__方法,指定pickle的序列化/反序列化逻辑,直接按枚举名恢复成员,跳过value匹配步骤:
class Site(Enum): GN = SiteInformation('North Site', 'Location String1') GS = SiteInformation('South Site', 'Location String2') def __reduce__(self): # 反序列化时直接通过类属性查找的方式返回对应枚举成员 return (getattr, (self.__class__, self.name))
这个方案兼容性更强,哪怕枚举值是不可哈希对象、复杂嵌套对象,也能正常完成序列化反序列化,不需要额外修改值类的逻辑。
注意:如果选择方案1,做相等判断的属性组合必须能唯一对应一个枚举成员,否则可能出现反序列化匹配到错误枚举项的问题。
内容的提问来源于stack exchange,提问作者Sebastian
相关产品推荐
相关产品推荐

