为什么 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
设定了标准,*和pickle
、json
、PyYAML
等都有紧随其后。
所以,问题是,为什么 marshal
是这样设计的?
好吧,你显然需要 loads
/dumps
;您无法在基于文件名的函数之上构建它们,而要在基于文件对象的函数之上构建它们,您需要 StringIO
,直到后来才出现。
你不一定需要load
/dump
,因为那些可以建立在loads
/[=16之上=]—但这样做可能会对性能产生重大影响:在将整个内容构建到内存中之前,您无法将任何内容保存到文件中,反之亦然,这对于大对象来说可能是个问题。
你绝对不需要基于文件名的 loadf
/dumpf
函数,因为这些可以在 load
/dump
之上简单地构建,使用没有性能影响,也没有用户可能会出错的棘手考虑。
一方面,无论如何拥有它们会很方便 — 并且有一些库,如 ElementTree
,确实具有类似的功能。它可能只为每个项目节省几秒钟和几行代码,但乘以数千个项目……
另一方面,它会使 Python 变大。如果您将这两个功能添加到每个模块(尽管这在 1.x 时代确实比现在多得多……),那么下载和安装它的额外 1K 并不是那么多,而是要记录更多,要学习更多,更值得记住。当然还有更多代码需要维护——每次你需要修复 marshal.dumpf
中的错误时,你必须记得去检查 pickle.dumpf
和 json.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
改变了,但它肯定不能在早期恢复。所以,这是保持小而简单的额外动力。
我经常在 Python 脚本和 IPython 笔记本中包含这个或类似的东西。
import cPickle
def unpickle(filename):
with open(filename) as f:
obj = cPickle.load(f)
return obj
这似乎是一个足够常见的用例,标准库应该提供一个功能来做同样的事情。有这样的功能吗?如果没有,怎么会?
stdlib 和 PyPI 上的大多数序列化库都有类似的 API。我很确定是marshal
设定了标准,*和pickle
、json
、PyYAML
等都有紧随其后。
所以,问题是,为什么 marshal
是这样设计的?
好吧,你显然需要 loads
/dumps
;您无法在基于文件名的函数之上构建它们,而要在基于文件对象的函数之上构建它们,您需要 StringIO
,直到后来才出现。
你不一定需要load
/dump
,因为那些可以建立在loads
/[=16之上=]—但这样做可能会对性能产生重大影响:在将整个内容构建到内存中之前,您无法将任何内容保存到文件中,反之亦然,这对于大对象来说可能是个问题。
你绝对不需要基于文件名的 loadf
/dumpf
函数,因为这些可以在 load
/dump
之上简单地构建,使用没有性能影响,也没有用户可能会出错的棘手考虑。
一方面,无论如何拥有它们会很方便 — 并且有一些库,如 ElementTree
,确实具有类似的功能。它可能只为每个项目节省几秒钟和几行代码,但乘以数千个项目……
另一方面,它会使 Python 变大。如果您将这两个功能添加到每个模块(尽管这在 1.x 时代确实比现在多得多……),那么下载和安装它的额外 1K 并不是那么多,而是要记录更多,要学习更多,更值得记住。当然还有更多代码需要维护——每次你需要修复 marshal.dumpf
中的错误时,你必须记得去检查 pickle.dumpf
和 json.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
改变了,但它肯定不能在早期恢复。所以,这是保持小而简单的额外动力。