web-dev-qa-db-ja.com

なぜ発電機を酸洗いできないのですか?

Pythonのピクルス(ここでは標準Python 2.5/2.6/2.7)は、ロックやファイルオブジェクトなどをピクルスできません。

また、pickleは実際には名前参照のみを格納するため、ジェネレーターとラムダ式(またはその他の匿名コード)をpickle化することはできません。

ロックとOSに依存する機能の場合、それらをピクルスできない理由whyは明白であり、理にかなっています。

しかしなぜ発電機を漬けられないのですか?


:わかりやすくするために-基本的な理由(またはその設計上の決定に使用された仮定と選択)に興味がありますwhy、「ピクルスエラーが発生するため」ではありません。

質問の目的が少し広いことに気付いたので、あなたが答えたかどうかの経験則は次のとおりです。「これらの仮定が提起された場合、または許可された発電機のタイプが何らかの形で制限された場合、酸洗い発電機は再び機能しますか?」

39
Radim

これに関する多くの情報が利用可能です。この問題に関する「公式ワード」については、 (closed)Pythonバグトラッカーの問題 をお読みください。

決定を下した人の一人による中心的な推論は、 このブログ に詳述されています:

ジェネレーターは本質的に強化された関数であるため、Pythonのバージョン間で下位互換性が保証されないバイトコードと、ローカル変数、クロージャー、およびジェネレーターの状態を保持するフレームを保存する必要があります。命令ポインタ。そして、この後者は、基本的にインタプリタ全体を選択可能にする必要があるため、達成するのがかなり面倒です。したがって、pickle化ジェネレーターをサポートするには、CPythonのコアに多数の変更を加える必要があります。

これで、pickleでサポートされていないオブジェクト(ファイルハンドル、ソケット、データベース接続など)がジェネレーターのローカル変数で発生した場合、ジェネレーターのpickleサポートに関係なく、そのジェネレーターは自動的にpickle化できませんでした。実装します。したがって、その場合でも、カスタムの__getstate__メソッドと__setstate__メソッドを提供する必要があります。この問題により、ジェネレーターのピクルスサポートがかなり制限されます。

そして、2つの推奨される回避策が記載されています。

とにかく、そのような機能が必要な場合は、Stackless Pythonを調べてください。これは上記のすべてを実行します。Stacklessのインタープリターは選択可能であるため、プロセスの移行も無料で行えます。これは、中断できることを意味します。タスクレット(Stacklessのグリーンスレッドの名前)、ピクルス、ピクルスを別のマシンに送信、ピクルスを外し、タスクレットを再開すると、プロセスを移行したばかりです。これは非常に優れた機能です。

しかし、私の謙虚な意見では、ジェネレーターを単純なイテレーター(つまり、__next__メソッドを持つイテレーター)として書き直すというこの問題の最善の解決策です。イテレータは、状態が明示的であるため、スペース的に簡単かつ効率的に酸洗いできます。ただし、外部状態を明示的に表すオブジェクトを処理する必要があります。これを回避することはできません。

49
agf

実装によっては、実際に可能です。 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では、選択可能なジェネレーターをシミュレートするために イテレーターオブジェクト を作成することもできます。

24
zeekay