为什么 Python 不包含从文件名加载 pickle 的函数?

How come Python does not include a function to load a pickle from a file name?

我经常在 Python 脚本和 IPython 笔记本中包含这个或类似的东西。

import cPickle
def unpickle(filename):
    with open(filename) as f:
        obj = cPickle.load(f)
    return obj

这似乎是一个足够常见的用例,标准库应该提供一个功能来做同样的事情。有这样的功能吗?如果没有,怎么会?

stdlib 和 PyPI 上的大多数序列化库都有类似的 API。我很确定是marshal设定了标准,*picklejsonPyYAML等都有紧随其后。

所以,问题是,为什么 marshal 是这样设计的?

好吧,你显然需要 loads/dumps;您无法在基于文件名的函数之上构建它们,而要在基于文件对象的函数之上构建它们,您需要 StringIO,直到后来才出现。

你不一定需要load/dump,因为那些可以建立在loads/[=16之上=]—但这样做可能会对性能产生重大影响:在将整个内容构建到内存中之前,您无法将任何内容保存到文件中,反之亦然,这对于大对象来说可能是个问题。

你绝对不需要基于文件名的 loadf/dumpf 函数,因为这些可以在 load/dump 之上简单地构建,使用没有性能影响,也没有用户可能会出错的棘手考虑。

一方面,无论如何拥有它们会很方便 — 并且有一些库,如 ElementTree,确实具有类似的功能。它可能只为每个项目节省几秒钟和几行代码,但乘以数千个项目……

另一方面,它会使 Python 变大。如果您将这两个功能添加到每个模块(尽管这在 1.x 时代确实比现在多得多……),那么下载和安装它的额外 1K 并不是那么多,而是要记录更多,要学习更多,更值得记住。当然还有更多代码需要维护——每次你需要修复 marshal.dumpf 中的错误时,你必须记得去检查 pickle.dumpfjson.dumpf 以确保它们不需要更改,有时你会不记得。

平衡这两个考虑因素确实是一个判断问题。几十年前有人制作的,此后可能没有人真正讨论过。如果您认为今天有必要对其进行更改,您可以随时 post 在 the issue tracker or start a thread on python-ideas.

上提出功能请求

* 不在 the original 1991 version of marshal.c; that just had load and dump. Guido added loads and dumps in 1993 中,作为主要描述为 "Add separate main program for the Mac: macmain.c" 的更改的一部分。大概是因为 Python 解释器内部的某些东西需要转储并加载到字符串。**

** marshal 用作导入 .pyc 文件等操作的基础。这也意味着(至少在 CPython 中)它不仅在 C 中实现,而且静态地内置到解释器本身的核心中。虽然我认为它实际上 可以 变成一个常规模块,因为 3.4 import 改变了,但它肯定不能在早期恢复。所以,这是保持小而简单的额外动力。