栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

读取泡菜文件时发生AttributeError

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

读取泡菜文件时发生AttributeError

当您将内容转储到a中时

pickle
,应避免对主模块中声明的类和函数进行酸洗。您的问题是(部分地)因为程序中只有一个文件。
pickle
是惰性的,不会序列化类定义或函数定义。相反,它保存了有关如何查找类的参考(类所在的模块及其名称)。

当python直接运行脚本/文件时,它将作为

__main__
模块运行程序(无论其实际文件名如何)。但是,当加载文件而 不是
主模块时(例如,当您执行类似操作时
import program
),则其模块名称将基于其名称。因此
program.py
被称为
program

从命令行运行时,您正在执行前者,并且该模块称为

__main__
。因此,pickle会创建对类的引用
__main__.Signal
。当
spyder
尝试加载pickle文件时,它会被告知要导入
__main__
并查找
Signal
。但是,spyder的
__main__
模块是用于启动的模块,
spyder
而不是您自己的模块,
program.py
因此pickle找不到
Signal

您可以通过运行检查pickle文件的内容(

-a
显示每个命令的描述)。由此您将看到您的班级被引用为
__main__.Signal

python -m pickletools -a file.pkl

您会看到类似以下内容:

    0: x80 PROTO      3   Protocol version indicator.    2: c    GLOBAL     '__main__ Signal' Push a global object (module.attr) on the stack.   19: q    BINPUT     0      Store the stack top into the memo.  The stack is not popped.   21: )    EMPTY_TUPLE       Push an empty tuple.   22: x81 NEWOBJ Build an object instance.   23: q    BINPUT     1      Store the stack top into the memo.  The stack is not popped.   ...   51: b    BUILD  Finish building an object, via __setstate__ or dict update.   52: .    STOP   Stop the unpickling machine.highest protocol among oppres = 2

解决方案

有许多解决方案可供您选择:

  1. 不要序列化
    __main__
    模块中定义的类的实例。最简单,最好的解决方案。而是将这些类移到另一个模块,或编写
    main.py
    脚本来调用您的程序(这都意味着在
    __main__
    模块中不再找到此类)。
  2. 编写自定义解串器
  3. 编写自定义序列化器

以下解决方案将与

out.pkl
由以下代码创建的,名为pickle的文件一起使用(在名为的文件中
program.py
):

import pickleclass MyClass:    def __init__(self, name):        self.name = nameif __name__ == '__main__':    o = MyClass('test')    with open('out.pkl', 'wb') as f:        pickle.dump(o, f)

定制解串器解决方案

您可以编写一个客户反序列化程序,该程序知道何时遇到对

__main__
模块的引用,您真正要指的是
program
模块。

import pickleclass MyCustomUnpickler(pickle.Unpickler):    def find_class(self, module, name):        if module == "__main__": module = "program"        return super().find_class(module, name)with open('out.pkl', 'rb') as f:    unpickler = MyCustomUnpickler(f)    obj = unpickler.load()print(obj)print(obj.name)

这是加载已创建的泡菜文件的最简单方法。该程序是将责任推到反序列化代码上,而正确地创建泡菜文件应该真正由序列化代码负责。

定制序列化解决方案

与以前的解决方案相比,您可以确保任何人都可以轻松地对序列化的pickle对象进行反序列化,而无需了解自定义反序列化逻辑。为此,您可以使用

copyreg
模块通知
pickle
如何反序列化各种类。因此,在这里,您要做的是告诉
pickle
所有
__main__
类实例反序列化,就好像它们是
program
类实例一样。您将需要为每个类注册一个自定义序列化程序

import programimport pickleimport copyregclass MyClass:    def __init__(self, name):        self.name = namedef pickle_MyClass(obj):    assert type(obj) is MyClass    return program.MyClass, (obj.name,)copyreg.pickle(MyClass, pickle_MyClass)if __name__ == '__main__':    o = MyClass('test')    with open('out.pkl', 'wb') as f:        pickle.dump(o, f)


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/626427.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号