43

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

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

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

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


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

質問の目的が少し広いことを理解しているので、あなたが答えたかどうかの経験則は次のとおりです。

4

2 に答える 2

54

これについてはたくさんの情報があります。この問題に関する「公式の言葉」については、(クローズされた)Pythonバグトラッカーの問題をお読みください。

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

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

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

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

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

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

于 2011-08-24T18:29:08.457 に答える
26

実装によっては、実際に可能です。PyPyStacklessPythonはどちらもこれを可能にします(とにかくある程度):

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

于 2011-08-24T18:31:31.830 に答える