pyspark 中的 PicklingError(PicklingError: Can't pickle <class '__main__.Person'>: __main__ 上的属性查找 Person 失败)

数据挖掘 Python 阿帕奇火花 pyspark 天蓝色毫升 泡菜
2022-03-02 05:38:05

我无法腌制以下课程。我正在使用数据块 6.5 ML(包括 Apache Spark 2.4.5、Scala 2.11)

import pickle
class Person:
  def __init__(self, name, age):
    self.name = name
    self.age = age
p1 = Person("John", 36)
pickle.dump(p1,open('d.pkl','wb'))```

PicklingError: Can't pickle <class '__main__.Person'>: attribute lookup Person on __main__ failed
2个回答

从这里可能的答案

问题是您试图从定义它的模块中提取一个对象。如果您将该类移动到一个单独的文件中并将其导入到您的脚本中,那么它应该可以工作。

不过,该解决方案在 iPython 笔记本中对我来说是不可行的。所以在这里我从这里获得一些额外的信息

Python 的 pickle 实际上不会序列化类:它会序列化实例,并在序列化中放入对每个实例类的引用——并且该引用基于类绑定到定义明确的模块中的名称。因此,没有模块名称但作为其他类中的属性或列表和字典中的数据存在的类的实例通常不起作用。

人们可以尝试做的一件直接的事情是尝试使用莳萝而不是泡菜。它是一个第三方包,其工作方式类似于“pickle”,但具有实际序列化任意动态类的扩展。

虽然使用 dill 可能会帮助其他人到达这里,但这不是你的情况,因为为了使用 dill,你必须修改 PySpark 使用的底层 RPC 机制来使用 dill 而不是 pickle,这可能不会对生产使用来说是微不足道的,也不够一致。

如果问题真的是关于动态创建的类是不可选择的,那么您可以做的是为动态类本身创建额外的元类,而不是使用“类型”,并在这些元类上创建正确的getstatesetstate(或其他辅助方法,因为它在 pickle 文档中) - 这可能使这些类能够被普通的 Pickle 腌制。也就是说,使用 Pickler 辅助方法的单独元类代替代码中的 type(..., (object, ), ...) 。

但是,“不可拾取的对象”不是您遇到的错误 - 这是一个属性查找错误,这表明您正在构建的结构不足以让 Pickle 对其进行反省并从您的一个实例中获取所有成员 - 它(尚未)与类对象的不可腌制性无关。由于您的动态类作为类的属性(它本身不是腌制的)而不是实例的属性,所以腌制很可能不关心它。检查上面pickle的文档,也许你需要的只是适当的辅助方法来腌制你的班级,元类上没有什么不同,你可以在那里正常工作。

不要定义一个类,而是尝试定义一个 NamedTuple。

import pickle
from collections import namedtuple

Person = namedtuple("Person", "name age")

p1 = Person("John", 36)
pickle.dump(p1,open('d.pkl','wb'))