为什么发酵机不能被腌制?

Rad*_*dim 36 python generator pickle python-stackless

Python的泡菜(我说的是标准的Python 2.5/2.6/2.7)不能腌制锁,文件对象等.

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

在锁和依赖于操作系统的功能的情况下,原因为何你不能咸菜他们是明显的,是有道理的.

为什么你不能发泡?


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

我意识到这个问题有点广泛的目标,所以这里有一个经验法则,你是否回答:"如果这些假设被提出,或者允许的发电机的类型在某种程度上受到限制,那么酸洗发电机会再次工作吗?"

agf*_*agf 48

有很多关于这方面的信息.有关该问题的"官方消息",请阅读(已关闭)Python bugtracker问题.

由做出决定的人之一的核心推理在此博客上详细说明:

由于生成器本质上是一个加强函数,我们需要保存它的字节码,它不能保证在Python的版本之间向后兼容,并且它的框架保持生成器的状态,如局部变量,闭包和指令指针.而后者实现起来相当麻烦,因为它基本上需要使整个解释器可以选择.因此,对酸洗发生器的任何支持都需要对CPython核心进行大量更改.

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

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

无论如何,如果你需要这样的功能,那么请看看Stackless Python,它可以完成上述所有工作.由于Stackless的解释器是可选择的,因此您也可以免费获得进程迁移.这意味着你可以中断一个tasklet(Stackless的绿色线程的名称),pickle它,将pickle发送到另一台机器,unpickle它,恢复tasklet,并且你刚刚迁移了一个进程.这是一个很酷的功能!

但在我看来,这个问题的最佳解决方案是将生成器重写为简单的迭代器(即带有__next__方法的迭代器).迭代器在空间方面很容易和有效,因为它们的状态是明确的.但是,您仍然需要明确地处理表示某个外部状态的对象; 你不能绕过这个.

  • 你怎么能同时提供答案和投票“关闭”?现在我好奇地等待“辩论、争论和扩展讨论”:-) (2认同)
  • 我一开始误读了你的问题,你不能收回近距离投票。我也是第一个投票决定重新开放的人。 (2认同)

zee*_*kay 23

你实际上可以,具体取决于实现.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
Run Code Online (Sandbox Code Playgroud)

在CPython中,还可以创建一个迭代器对象来模拟可选择的生成器.