【问题标题】:How can I pickle a class definition?我怎样才能腌制一个类定义?
【发布时间】:2019-03-04 09:53:35
【问题描述】:

我在挑选一个类从另一个模块导入一个类时遇到问题。

想象一下,我有一个文件 classA.py,其中定义了 A 类:

class A:
    def execute(self):
        print('Hello from class A!')

然后我还有另一个文件classB.py:

import dill
import classA

class B:
    def __init__(self):
        self.a = classA.A()

    def execute(self):
        self.a.execute()
        print('Hello from class B!')


b = B()

with open('/file/path', 'wb') as f:
    dill.dump(b, f)

如果然后我尝试从不同的目录中解压缩创建的文件:

with open('file/path', 'rb') as f:
    b = dill.load(f)

我得到错误:

ModuleNotFoundError: No module named 'classB'

它当然可以在我拥有文件 classA.py 和 classB.py 的同一个文件夹中工作,因为解释器可以找到这两个类的定义。

所以我想我必须以某种方式将类的定义带入 pickle 文件。我该怎么做?

谢谢 斯特凡诺

【问题讨论】:

  • dill库是否导入成功?
  • 是的,莳萝没有问题
  • 当我尝试在与我创建文件的会话不同的会话中解压文件时,问题就出现了
  • “不同的会话”是什么意思?

标签: python class pickle definition


【解决方案1】:

它当然可以在我拥有文件 classA.py 和 classB.py 的同一个文件夹中工作,因为解释器可以找到这两个类的定义。 所以我想我必须以某种方式将类的定义带入泡菜文件。我该怎么做?

这不是它的工作原理。您不会“将类的定义带入 pickle 文件” - which would make no sense 因为只有类限定名被腌制(限定名 => 包名.模块名.类名)

相反,您必须确保在 unpickling 时定义类的模块是可导入的 - “可导入”意味着包或模块的父文件夹路径位于您的 sys.path 中。您可以通过几种方式执行此操作(使用 PYTHONPATH 环境变量,直接在您的代码中弄乱sys.path - 这通常是一个坏主意,有时是正确的解决方案 - 在 vi​​rtualenv 中安装您的模块并激活此 virtualenv 等)

注意:当前工作目录总是在您的sys.path 中排在第一位,这就是“它当然可以在同一个文件夹中工作”的原因。

【讨论】:

  • 感谢您的回答!我注意到,如果我将类的定义放在我转储 B 类的同一个文件中,我不需要让模块可以导入。pickle 可以在任何地方提取。为什么会有这样的行为?无法复制在其他文件中定义的相同类?
  • 如果类def在同一个模块中,那么当你调用pickle.load()时它已经被导入,并且“复制”这种行为实际上是“使模块可导入”的全部意义。这只是常识:您需要类对象(是的,“类对象”-python 类、函数、模块等在运行时是像任何其他对象一样的对象)来创建它的实例,并且您不能使用不存在。 pickle.load() 负责导入定义类的模块(如果模块尚未在 sys.modules 缓存中)并从中获取类对象。
  • 好的,所以没有办法创建一个泡菜,这样我就可以把它交给任何人,他/她将能够加载和使用它,除非我定义了所有使用的类在同一个我用来转储classB的模块,对吧?我将始终必须提供包含 classA 的模块
  • Pickling 是关于数据,而不是代码,所以是的,很明显你必须拥有与 pickle 一起使用的代码。
猜你喜欢
  • 1970-01-01
  • 2016-11-25
  • 2017-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-03
  • 2019-09-01
相关资源
最近更新 更多