问题 在不同文件中加载pickled对象 - 属性错误


我在一个模块中加载一个pickle文件时有些麻烦,该模块与我腌制文件的模块不同。我知道以下线程: 无法使用pickle和multipile模块加载文件。我已经尝试了将类导入到模块中的建议解决方案,我将取消我的文件,但它一直给我同样的错误: AttributeError: Can't get attribute 'Document' on <module '__main__' from ''>

我想要做的基本结构:

Util文件,用于pickles和unpickles对象,utils.py:

import pickle

def save_document(doc):

    from class_def import Document

    write_file = open(file_path, 'wb')
    pickle.dump(doc, write_file)

def load_document(file_path):
    from class_def import Document

    doc_file = open(file_path, 'rb')
    return pickle.load(doc_file)

文件定义了Document对象并调用了save util方法,class_def.py:

import utils

class Document(object):
    data = ""

if __name__ == '__main__':
    doc = Document()
    utils.save_document(doc)

调用load util方法的文件,process.py:

import utils

if __name__ == '__main__':
     utils.load_document(file_path)

运行process.py会给出上面提到的AttributeError。如果我将class_def.py文件导入process.py并运行其原始线程中提到的main方法,它可以工作,但我希望能够单独运行这两个模块,因为class_def文件是一个预处理步骤,需要相当一段时间我该怎么解决这个问题?


12602
2017-10-27 14:45


起源

不回答您的问题,但您应该在打开文件处理程序后关闭文件处理程序,或者只是使用 with。 - Itay
当文件正在运行时 __main__ 任何在其中定义的东西被腌制成为成员 __main__ 模块,所以如果你然后加载到另一个文件它失败。你只需要从其他模块中腌制东西 __main__最快的解决办法是 from <this modules name> import * 但我不建议在生产代码中使用它。 - Tadhg McDonald-Jensen
可能重复 python pickle上的命名空间 但我认为可能有一个更好的线程标记为重复 - Tadhg McDonald-Jensen


答案:


在你的 class_def.py 文件你有这个代码:

if __name__ == '__main__':
    doc = Document()
    utils.save_document(doc)

这意味着 doc 将是一个 __main__.Document 对象,所以当它被腌制时,它期望能够得到一个 Document 从主模块的类,要修复这个你需要使用的定义 Document 来自一个名为的模块 class_def 意思是你要在这里添加一个导入:

if __name__ == '__main__':
    from class_def import Document 
    # ^ so that it is using the Document class defined under the class_def module
    doc = Document()
    utils.save_document(doc)

这样,它需要运行class_def.py文件两次,一次为 __main__ 一旦成为 class_def 但它确实意味着数据将被腌制成一个 class_def.Document 对象所以加载它将从正确的位置检索类。否则,如果你有办法从另一个文档对象构建一个文档对象,你可以做这样的事情 utils.py

def save_document(doc):
    if doc.__class__.__module__ == "__main__":
        from class_def import Document #get the class from the reference-able module
        doc = Document(doc) #convert it to the class we are able to use


    write_file = open(file_path, 'wb')
    pickle.dump(doc, write_file)

虽然通常我更喜欢第一种方式。


13
2017-10-27 15:46





我有类似的问题,只是意识到我们的实现之间的差异。

你的文件结构:

  • util.py
    • 定义泡菜功能
  • class_def.py
    • import util
    • 定义类
    • 制作实例
    • 叫保存泡菜
  • process.py
    • import util
    • 装酱菜

我的错误(使用你的文件名)是第一个:

  • util_and_class.py
    • 定义类
    • 定义泡菜功能
    • 制作实例
    • 叫保存泡菜
  • process.py
    • import util_and_class
    • call load pickle << ERROR

什么解决了我的泡菜导入问题:

  • util_and_class.py
    • 定义类
    • 定义泡菜功能
  • pickle_init.py
    • import util_and_class
    • 制作实例
    • 叫保存泡菜
  • process.py
    • 呼叫负载泡菜

这有一个受欢迎的副作用,我不需要导入util_and_class文件,因为它被烘焙到pickle文件中。调用实例并将pickle保存在单独的文件中解决了问题 __name__ 问题在于 “在一个与我腌制文件的模块不同的模块中加载一个pickle文件。”


2
2017-08-05 23:44