web-dev-qa-db-ja.com

python関数をピクルする(またはコードをシリアル化する)簡単な方法はありますか?

ネットワーク接続を介して機能を転送しようとしています(非同期機能を使用)。このような転送のためにpython関数(この場合は少なくともこの場合、副作用はありません)をシリアル化する簡単な方法はありますか?

理想的には、次のような機能のペアが必要です。

def transmit(func):
    obj = pickle.dumps(func)
    [send obj across the network]

def receive():
    [receive obj from the network]
    func = pickle.loads(s)
    func()
90
Michael Fairley

関数バイトコードをシリアル化し、呼び出し元で再構築できます。 marshal モジュールを使用してコードオブジェクトをシリアル化し、それを関数に再アセンブルできます。すなわち:

import marshal
def foo(x): return x*x
code_string = marshal.dumps(foo.func_code)

次に、リモートプロセスで(code_stringを転送した後):

import marshal, types

code = marshal.loads(code_string)
func = types.FunctionType(code, globals(), "some_func_name")

func(10)  # gives 100

いくつかの注意事項:

  • marshalの形式(任意のpythonバイトコード)は、メジャーpythonバージョン間で互換性がない場合があります。

  • Cpython実装でのみ機能します。

  • 関数がピックアップする必要があるグローバル(インポートされたモジュール、他の関数などを含む)を参照する場合、これらもシリアル化するか、リモート側で再作成する必要があります。私の例では、リモートプロセスのグローバル名前空間を指定しています。

  • クロージャーやジェネレーター関数などのより複雑なケースをサポートするには、おそらくもう少し行う必要があります。

113
Brian

Dill を確認してください。これは、Pythonのpickleライブラリを拡張して、関数を含むより多くのタイプをサポートします。

>>> import dill as pickle
>>> def f(x): return x + 1
...
>>> g = pickle.dumps(f)
>>> f(1)
2
>>> pickle.loads(g)(1)
2

また、関数のクロージャー内のオブジェクトへの参照もサポートしています。

>>> def plusTwo(x): return f(f(x))
...
>>> pickle.loads(pickle.dumps(plusTwo))(1)
3
36
Josh Rosen

Pyroこれをあなたのために にできます。

14
RichieHindle

最も簡単な方法は、おそらくinspect.getsource(object)inspect module を参照)であり、関数またはメソッドのソースコードを含むStringを返します。

10
Aaron Digulla

それはすべて、実行時に関数を生成するかどうかに依存します。

実行すると、inspect.getsource(object)は_.py_ファイルからオブジェクトのソースを取得するため、動的に生成された関数では機能しません。したがって、実行前に定義された関数のみがソースとして取得できます。

とにかく関数がファイルに配置されている場合、レシーバーにそれらへのアクセスを許可せず、モジュールと関数名のみを渡すようにしてください。

私が考えることができる動的に作成された関数の唯一の解決策は、送信前に関数を文字列として構築し、ソースを送信し、次に受信側でeval()します。

編集:marshalソリューションも非常にスマートに見えますが、組み込みのその他の何かをシリアル化できることを知りませんでした

6
kurczak

cloudパッケージ(pip install cloud)は、依存関係を含む任意のコードをpickleできます。 https://stackoverflow.com/a/16891169/1264797 を参照してください。

5
stevegt
code_string = '' '
 def foo(x):
 return x * 2 
 def bar(x):
 return x ** 2 
 '' '
 
 obj = pickle.dumps(code_string)
 

いま

 exec(pickle.loads(obj))
 
 foo(1)
> 2 
 bar(3)
> 9 
1
Yanni Papadakis

このモジュールで使用される基本的な機能はクエリをカバーし、さらに回線を介して最高の圧縮を実現します。有益なソースコードを参照してください。

y_serial.pyモジュール:: warehouse Python SQLiteのオブジェクト

「シリアル化+永続化::数行のコードで、PythonオブジェクトをSQLiteに圧縮して注釈を付けます。その後、SQLを使用せずにキーワードで時系列にそれらを取得します。スキーマレスデータを保存します。」

http://yserial.sourceforge.net

1
code43