Python 2与Python 3字符串Pickling结果不一致的解决方法
解决Python2与Python3字符串Pickle结果不一致的问题
这个问题我之前也碰到过,核心原因就是Python2和Python3里str类型的本质差异:Python2的str等价于Python3的bytes(字节串),而Python3的str是Unicode字符串。哪怕指定了protocol=2(跨版本兼容的协议),类型本身的区别还是会导致Pickle输出不一样。
下面是两种可靠的解决方案,能让两边的Pickle结果完全一致:
方法1:显式转换为字节串后再Pickle
最直接的思路是统一把要序列化的字符串转换成字节类型,再进行Pickle操作,这样两边序列化的是完全相同的内容:
在Python3中操作
把Unicode字符串(str)编码成bytes(推荐用UTF-8编码,保证兼容性):
import pickle my_str = "Hello, Pickle!" # 先将Unicode字符串编码为字节串 my_bytes = my_str.encode('utf-8') # 用protocol=2序列化 pickled_data = pickle.dumps(my_bytes, protocol=2)
在Python2中操作
Python2的str本身就是字节串,但如果你的字符串是unicode类型,需要先编码成str:
import pickle my_unicode = u"Hello, Pickle!" # 将Unicode编码为字节串(str类型) my_str = my_unicode.encode('utf-8') # 用protocol=2序列化 pickled_data = pickle.dumps(my_str, protocol=2)
这样两边生成的pickled_data会完全一致,因为我们序列化的都是相同的字节内容。
方法2:自定义Pickler实现自动适配
如果不想每次手动转换,可以写一个自定义的Pickler类,自动处理两个版本的字符串类型差异,用起来更优雅:
import pickle class UnifiedStringPickler(pickle.Pickler): def save(self, obj): # Python3:把str(Unicode)转成bytes if isinstance(obj, str): obj = obj.encode('utf-8') # Python2:把unicode转成str(字节串) elif isinstance(obj, unicode): obj = obj.encode('utf-8') super(UnifiedStringPickler, self).save(obj) # 封装成统一的序列化函数 def unified_dumps(obj, protocol=2): from io import BytesIO buffer = BytesIO() pickler = UnifiedStringPickler(buffer, protocol=protocol) pickler.dump(obj) return buffer.getvalue() # 测试示例 # Python3中调用 data = unified_dumps("Hello, World!", protocol=2) # Python2中调用 data = unified_dumps(u"Hello, World!", protocol=2)
反序列化的对应处理
反序列化时也要做逆向转换,确保拿到符合当前Python版本的字符串类型:
def unified_loads(pickled_data): obj = pickle.loads(pickled_data) # Python3:把bytes转回str(Unicode) if isinstance(obj, bytes): return obj.decode('utf-8') # Python2:把str转回unicode elif isinstance(obj, str): return obj.decode('utf-8') return obj
为什么protocol=2还会有差异?
虽然protocol=2是Python2和Python3都支持的最高兼容协议,但它只定义了Pickle的序列化格式结构,并没有消除两种版本中str类型的本质区别:
- Python2中Pickle
str时,会标记为S类型(字节字符串) - Python3中Pickle
str时,会标记为V类型(Unicode字符串)
只有当两边序列化的是相同类型的对象(比如都是字节串),protocol=2才能保证输出一致。
内容的提问来源于stack exchange,提问作者JoaoAlby
相关产品推荐
相关产品推荐

