17

マシン A でシリアライズし、マシン B で Python ラムダをデシリアライズしたいと思います。これには明らかな問題がいくつかあります。

  • pickle モジュールはコードをシリアライズまたはデシリアライズしません。クラス/メソッド/関数の名前のみをシリアル化します
  • Google で見つけた回答のいくつかは、低レベルのマーシャル モジュールを使用してラムダの func_code 属性をシリアル化することを示唆していますが、逆シリアル化されたコード オブジェクトから関数オブジェクトを再構築する方法を説明していません。
  • marhshal(l.func_code) は、ラムダに関連付けられたクロージャーをシリアル化しません。これにより、特定のラムダがクロージャーを本当に必要とする時期を検出し、クロージャーを使用するラムダをシリアル化しようとしていることをユーザーに警告するという問題が発生します。

したがって、私の質問:

  • デシリアライズされた (デマーシャリングされた) コード オブジェクトから関数を再構築するにはどうすればよいでしょうか。
  • 関連するクロージャーがないと、特定のラムダが適切に機能しないことをどのように検出しますか?
4

2 に答える 2

21

驚くべきことに、関連付けられたクロージャーなしでラムダが機能するかどうかを確認することは、実際にはかなり簡単です。データモデルのドキュメント によると、func_closure属性を確認するだけです:

>>> def get_lambdas():
... バー = 42
... return (ラムダ: 1, ラムダ: バー)
...
>>> no_vars、vars = get_lambdas()
>>> no_vars.func_closure を出力
なし
>>> 印刷 vars.func_closure
(<0x1020d3d70 のセル: 0x7fc150413708 の int オブジェクト>)
>>> 印刷 vars.func_closure[0].cell_contents
42
>>>

次に、ラムダのシリアル化とロードはかなり簡単です。

>>> インポートマーシャル、タイプ
>>> 古い = ラムダ: 42
>>> old_code_serialized = marshal.dumps(old.func_code)
>>> new_code = marshal.loads(old_code_serialized)
>>> new = types.FunctionType(new_code, globals())
>>> 新しい()
42

次のドキュメントを参照する価値がありますFunctionType

関数(コード、グローバル[、名前[、argdefs [、閉鎖]]])

コード オブジェクトとディクショナリから関数オブジェクトを作成します。
オプションの名前文字列は、コード オブジェクトの名前をオーバーライドします。
オプションの argdefs タプルは、デフォルトの引数値を指定します。
オプションのクロージャ タプルは、自由変数のバインディングを提供します。

クロージャーを提供することもできることに注意してください…つまり、古い関数のクロージャーをシリアル化して、反対側でロードすることさえできるかもしれません:)

于 2012-08-09T07:12:51.687 に答える