代码之家  ›  专栏  ›  技术社区  ›  Stefano Borini

稳定的python序列化(例如,没有pickle模块重定位问题)

  •  0
  • Stefano Borini  · 技术社区  · 16 年前

    我正在考虑使用 Quantities 定义一个数字及其单位。这个值很可能必须存储在磁盘上。正如您可能意识到的,pickle有一个主要问题:如果您将模块重新放置在周围,则取消拾取将无法解决类,并且您将无法取消拾取信息。这种行为有解决办法,但实际上是解决办法。

    对于这个问题,我幻想的解决方案是创建一个唯一编码给定单元的字符串。一旦您从磁盘获得了这种编码,就将其传递给Quantities模块中的工厂方法,该方法将其解码为适当的单位实例。优点是,即使您重新定位模块,只要您将magic string令牌传递给工厂方法,一切都将继续工作。

    这是一个已知的概念吗?

    1 回复  |  直到 16 年前
        1
  •  1
  •   Alex Martelli    16 年前

    看起来像是惠勒第一原理的应用,“计算机科学中的所有问题都可以通过另一个间接层次来解决”(第二原理补充道,“但这通常会产生另一个问题”)—)。本质上,您需要做的是间接确定 类型 --类型内的实体可以使用类似酸洗的方法(您可以研究 pickle.py copy_reg.py 关于后者的所有细节)。

    具体地说,我认为您要做的是子类 pickle.Pickler 并覆盖 save_inst 方法。当当前版本显示:

        if self.bin:
            save(cls)
            for arg in args:
                save(arg)
            write(OBJ)
        else:
            for arg in args:
                save(arg)
            write(INST + cls.__module__ + '\n' + cls.__name__ + '\n')
    

    您希望编写的内容与类的模块和名称不同——类的某种唯一标识符(由两个字符串组成),可能保存在您自己的注册表或注册表中;以及 save_global 方法。

    对你的子类来说更容易 Unpickler ,因为 _instantiate 部分已在其自己的方法中分解:您只需要重写 find_class ,这是:

    def find_class(self, module, name):
        # Subclasses may override this
        __import__(module)
        mod = sys.modules[module]
        klass = getattr(mod, name)
        return klass
    

    它必须使用两个字符串并返回一个类对象;您可以再次通过注册表来实现这一点。

    像往常一样,当涉及到注册表时,您需要考虑如何确保注册所有感兴趣的对象(类)等。这里流行的一个策略是不要使用pickle,但要确保所有类的移动、模块的重命名等都被永久记录在某个地方;这样,仅仅子类unpickler就可以完成所有工作,它可以最方便地在重写的 查找\类 --跳过所有注册问题。我认为你认为这是一个“解决方法”,但对我来说,这似乎只是一个非常简单、强大和方便的“一个更高层次的间接”概念的实现,避免了“一个更大的问题”的问题;-)。

    推荐文章