Pickle功能正常但pytest测试失败,报AttributeError错误
问题原因
你遇到的报错核心是pickle无法序列化局部类的实例。在test_object fixture里,TestObject是定义在函数内部的局部类——pickle序列化对象时,需要能在全局命名空间中找到类的定义,但局部类的作用域仅限于函数内部,序列化时无法被准确定位,因此触发AttributeError。
解决方案
方案1:把测试类移到模块级(最推荐)
将TestObject从fixture函数中移到测试模块的顶层作用域,让pickle能找到类的全局引用:
# tests.test_persist.py from pathlib import Path import pytest from lib.persist import obj_pickle TEST_DIR = Path("test_dir") # 把TestObject移到模块顶层 class TestObject(): def __init__(self, instance_file_name): self.instance_file_name = instance_file_name self.data = "This is a test object." @pytest.fixture def test_object(): test_object = TestObject("test_object_file") return test_object def test_obj_pickle(test_object): obj_pickle(test_object, Path(TEST_DIR)) path = Path(TEST_DIR, "test_object_file" + ".pkl") assert path.exists()
方案2:自定义类的__reduce__方法
如果必须在fixture内部定义类,可以给类实现__reduce__方法,手动告诉pickle如何序列化/反序列化实例:
@pytest.fixture def test_object(): class TestObject(): def __init__(self, instance_file_name): self.instance_file_name = instance_file_name self.data = "This is a test object." def __reduce__(self): # 返回元组:(重建类的函数, 重建参数, 对象的状态字典) return (self.__class__, (self.instance_file_name,), self.__dict__) test_object = TestObject("test_object_file") return test_object
方案3:用cloudpickle替代标准pickle
cloudpickle是第三方库,支持序列化局部类、lambda等标准pickle不兼容的对象。先安装:
pip install cloudpickle
然后修改lib.persist.py的导入:
# lib.persist.py from pathlib import Path import cloudpickle as pickle # 替换成cloudpickle def obj_pickle(obj: object, dir:Path, protocol: int = None) -> None: """ Pickle an object to a byte file. """ if not dir.exists(): dir.mkdir(parents=True, exist_ok=True) path = Path(dir, obj.instance_file_name + '.pkl') with open(path, "wb") as file_handle: pickle.dump(obj, file_handle, protocol=protocol if protocol else pickle.HIGHEST_PROTOCOL) print(f"{obj.__class__.__name__} object {obj.instance_file_name} saved to {path}")
验证
修改完成后重新运行pytest,报错会消失,测试可正常通过。
内容的提问来源于stack exchange,提问作者Paul C
相关产品推荐
相关产品推荐

