如何让自定义collections.abc.Mapping子类被pickle序列化为dict?
问题描述
我实现了一个继承自collections.abc.Mapping混入接口的自定义外观类MyMapping,代码如下:
from collections import abc from typing import Mapping class MyMapping(abc.Mapping): def __init__(self, item:Mapping): self._item = item def __getitem__(self,key): return self._item[key] def __iter__(self): return iter(self._item) def __len__(self): return len(self._item)
我希望该类被pickle序列化时的结果与直接序列化dict完全一致,即满足:
import pickle # 期望该语句成立 pickle.dumps(MyMapping({'a':1})) == pickle.dumps({'a':1})
但我不想为了序列化就将所有此类实例手动转换为dict。我尝试过在__reduce__中返回以dict类型为首的元组,但并未生效。是否有其他简便方法?自定义可调用对象或注册分发归约函数的方式显得过于繁琐。
解决方案
你可以通过实现__reduce_ex__方法,让pickle在序列化时直接将MyMapping实例转换成对应的dict对象。__reduce_ex__是__reduce__的扩展版本,优先级更高,能覆盖默认的归约逻辑,适配不同的pickle协议版本。
修改后的代码如下:
from collections import abc from typing import Mapping import pickle class MyMapping(abc.Mapping): def __init__(self, item:Mapping): self._item = item def __getitem__(self,key): return self._item[key] def __iter__(self): return iter(self._item) def __len__(self): return len(self._item) def __reduce_ex__(self, protocol): # 返回dict类型和对应的参数,让pickle按dict规则序列化 return (dict, (dict(self),))
测试验证:
obj = MyMapping({'a':1}) print(pickle.dumps(obj) == pickle.dumps({'a':1})) # 输出 True
为什么之前的__reduce__没生效?
因为abc.Mapping的父类链(如collections.abc.Sized)可能间接影响了pickle的默认处理逻辑,而__reduce_ex__的优先级更高,能确保我们指定的序列化规则被执行。
内容的提问来源于stack exchange,提问作者Mark Rucker
相关产品推荐
相关产品推荐

