1

あるモジュールには、パラメーターの 1 つとして関数を必要とするクラスがあります。

class Foo():
    def __init__(self, fun):
        self.fun = fun

    def call_fun(self, arg):
        self.fun(arg)

別のモジュールには、このクラスのオブジェクトを作成するときに最終的にパラメーターとして渡す関数がいくつかあります。関数を簡単にカスタマイズするために、次の方法で値をバインドしています。

def sample_function(value):
    return (lambda arg: arg.effect(value))

Foo オブジェクトを初期化するときは、次のように値を渡します。

foo = Foo(sample_function(5))

後で、Foo オブジェクトを含むいくつかのオブジェクトを棚上げしたいと思いますが、すぐに不可能であることが判明しました (pickle モジュールが「TypeError: can't pickle function objects」を返すため)。私は pickle のシリアル化メカニズムの限界を十分に認識しており、これらのオブジェクトを pickle 化できない理由を理解しています。代わりに、クラスを再設計するか、他のシリアライズ手段を使用したいと考えています。プロパティを保持しながら Foo オブジェクトを棚上げできるように、これを再設計するにはどうすればよいですか?

4

1 に答える 1

3

コードの主な問題は、「sample_function」のクローズです。クロージャーがなければ、マーシャルとタイプのモジュールで実行できます。いくつかの例を次に示します。

import pickle
import marshal
import types

class Foo():
    def __init__(self, fun):
        self.fun = fun

    def call_fun(self, arg):
        self.fun(arg)

    def save(self, f):
        saved = self.fun
        self.fun = marshal.dumps(self.fun.func_code)
        pickle.dump(self, f)
        self.fun = saved

    @staticmethod
    def load(f):
        foo = pickle.load(f)
        foo.fun = types.FunctionType(marshal.loads(foo.fun), globals())
        return foo

def sample_function(arg):
    arg.effect(4)

class Arg():
    def effect(self, value):
        print "ok: " + str(value)

このクラスと関数を使用すると、以下を保存できます。

foo = Foo(sample_function)

f = open('foo', 'w')
foo.save(f)
f.close()

そしてロード:

f = open('foo', 'r')
foo = Foo.load(f)
f.close()

アイデアは、ピクルする前に「楽しみ」をマーシャリングし (そしてそれを復元して、クラスが壊れないようにする)、ロード時にマーシャリングされたコードを関数としてロードすることです。

しかし、それはクロージャーでは機能しません (クロージャーは呼び出し元の関数からの変数を必要とするため)。

于 2013-06-06T11:04:36.820 に答える