Python的泡菜(我说的是标准的Python 2.5 / 2.6 / 2.7)不能腌制锁,文件对象等。
它也不能pickle生成器和lambda表达式(或任何其他匿名代码),因为pickle实际上只存储名称引用。
如果是锁和操作系统相关的功能,为什么你不能腌制它们的原因显而易见并且有意义。
但是为什么你不能发酵生成器呢?
注意:为了清楚起见 - 我对基本原因(或设计决策中的假设和选择)感兴趣为什么,而不是“因为它会给你一个泡菜错误“。
我意识到这个问题有点广泛,所以这里有一个经验法则,你是否回答:“如果这些假设被提出,或者允许的发电机的类型在某种程度上受到限制,那么酸洗发电机会再次工作吗?” / p>
答案 0 :(得分:47)
有很多关于此的信息。有关该问题的“官方消息”,请阅读(closed) Python bugtracker issue。
做出决定的人之一的核心推理详见this blog:
由于生成器本质上是一个加强函数,我们需要保存它的字节码,它不保证在Python的版本之间是向后兼容的,并且它的帧保存了生成器的状态,例如局部变量,闭包和指令指针。而后者实现起来相当麻烦,因为它基本上需要使整个解释器可以选择。因此,对酸洗发生器的任何支持都需要对CPython核心进行大量更改。
现在,如果发生器的局部变量中出现了pickle不支持的对象(例如,文件句柄,套接字,数据库连接等),则无论是否有任何pickle支持,都无法自动对该生成器进行pickle。我们可能实施的发电机因此,在这种情况下,您仍需要提供自定义
__getstate__
和__setstate__
方法。这个问题使得对发电机的任何酸洗支持相当有限。
提到了两个建议的解决方法:
无论如何,如果你需要这样的功能,那么请看看Stackless Python,它可以完成上述所有工作。由于Stackless的解释器是可选择的,因此您也可以免费获得进程迁移。这意味着你可以中断一个tasklet(Stackless的绿色线程的名称),pickle它,将pickle发送到另一台机器,unpickle它,恢复tasklet,并且你刚刚迁移了一个进程。这是一个很酷的功能!
但是在我看来,这个问题的最佳解决方案是将生成器重写为简单的迭代器(即使用
__next__
方法的迭代器)。迭代器在空间方面很容易和有效,因为它们的状态是明确的。但是,您仍然需要明确地处理表示某个外部状态的对象;你无法解决这个问题。
答案 1 :(得分:21)
您实际上可以,具体取决于实施情况。 PyPy和Stackless 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中,还可以创建iterator object来模拟可选择的生成器。