繁体   English   中英

为什么不能腌制发电机?

[英]Why can't generators be pickled?

Python的pickle(我在这里说的是标准的Python 2.5 / 2.6 / 2.7)不能pickle锁,文件对象等。

它也不能腌制生成器和lambda表达式(或任何其他匿名代码),因为腌制实际上仅存储名称引用。

在锁和依赖于操作系统的功能的情况下, 为什么你不能腌制他们的理由是显而易见的,是有道理的。

但是为什么不能腌制发电机呢?


:只是为了清楚起见, -我有兴趣的根本原因(或假设和进入该设计决策选择) 为什么不“因为它给你一个味酸错误”。

我意识到这个问题的目的是广泛的,因此,以下经验法则是您是否回答的:“如果提出这些假设,或者允许的发生器类型受到更多限制,酸洗发生器会再次起作用吗?”

关于此的信息很多。 有关该问题的“官方词汇”,请阅读(已关闭)Python Bugtracker问题

博客详细介绍了做出决定的人之一的核心推理:

由于生成器本质上是一个强大的功能,因此我们需要保存其字节码,这不能保证在Python版本和其框架之间可以向后兼容,该框架保留了生成器的状态,例如局部变量,闭包和指令指针。 后者很难完成,因为它基本上需要使整个解释器可腌制。 因此,对酸洗生成器的任何支持都需要对CPython的核心进行大量更改。

现在,如果在生成器的局部变量中出现了不被pickle支持的对象(例如,文件句柄,套接字,数据库连接等),则该生成器将无法自动被腌制,无论我们对生成器的任何pickle支持如何实行。 因此,在那种情况下,您仍然需要提供自定义__getstate____setstate__方法。 这个问题使得对酸洗机的任何酸洗支持都相当有限。

并提到了两个建议的解决方法:

无论如何,如果您需要这样的功能,请查看可完成上述所有操作的Stackless Python。 而且,由于Stackless的解释器是可提取的,因此您还可以免费获得进程迁移。 这意味着您可以中断小任务(Stackless的绿色线程的名称),对其进行腌制,将其发送到另一台机器,对其进行腌制,继续执行该小任务,然后查看刚刚迁移的进程。 这真是太酷了!

但是,以我的拙见,将这个生成器重写为简单的迭代器(即使用__next__方法的生成器)是解决此问题的最佳方法。 因为迭代器的状态是明确的,所以它们在空间上很容易进行腌制。 但是,您仍然需要处理显式表示某些外部状态的对象。 你无法解决这个问题。

您实际上可以,具体取决于实现方式。 PyPyStackless Python都允许这样做(无论如何在某种程度上):

Python 2.7.1 (dcae7aed462b, Aug 17 2011, 09:46:15)
[PyPy 1.6.0 with GCC 4.0.1] on darwin
Type "help", "copyright", "credits" or "license" for more information.
And now for something completely different: ``Not your usual analyses.''
>>>> import pickle
>>>> gen = (x for x in range(100))
>>>> next(gen)
0
>>>> pickled = pickle.dumps(gen)
>>>> next(pickle.loads(pickled))
1

在CPython中,还可以创建一个迭代器对象来模拟可拾取的生成器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM