13

クラスを定義するスクリプトがある場合:

script = """

class myClass:
    def __init__(self):
        self.name = 'apple'
        self.color = 'green'

"""

次に、このスクリプトを独自の名前空間 dict で実行します。

NS = {}
exec script in NS

次に、クラスのインスタンスを作成してピクルします。

a = NS['myClass']()

import pickle

save = pickle.dumps(a)

今、それを解凍しようとすると:

load = pickle.loads(save)

エラーが発生します

AttributeError: 'module' object has no attribute 'myClass'

オブジェクトを再構築するために myClass を見つける場所を python が知らないため、これは機能しないと思います。しかし、 myClass は NS dict に存在します。pickle がロードしているオブジェクトのクラスを見つける場所を pickle に伝える方法はありますか?

4

2 に答える 2

5

実際にはさらに一歩進んで、オブジェクトを任意のタイプに再構築することができます。

import pickle
import copy_reg

class myClass(object):
    def __init__(self):
        self.apple = 'banana'

class otherclass(object):
    def __init__(self):
        self.apple = 'existential woe'

def pickle_an_object(o):
    print "pickling %s" % str(o)
    return otherclass, (o.apple,)

copy_reg.pickle(myClass, pickle_an_object)

foo = myClass()

s = pickle.dumps(foo)

del myClass
del otherclass

class otherclass(object):
    def __init__(self, appletype):
        self.apple = 'not %s' % appletype

o2 = pickle.loads(s)

print o2.apple

基本的な考え方は、クラスをある種の「トロイの木馬」に詰め込み、その再構築によって元のクラスとは異なるクラスがインスタンス化されるというものです。

酸洗面の内容は問わないotherclass。重要なのは、それが「宛先」クラスと同じモジュールパスに存在することpickleだけです-モジュール名の文字列表現をシリアル化されたストリームに入れるだけです。

したがって、上記のコードで何が起こっているかを詳細に分析するには、次のようにします。

  • のカスタム ピッカーを登録しmyClassます。copy_regこれは、 または__reduce_ex__関数を介して行うことができます。
  • 私たちのカスタム pickler は、「これをotherclass" のインスタンスとして pickle します (これはダミーです。pickle に入れるのはモジュール/クラス名だけなので、pickle 側での「実際の」内容は必要ありません)」と言います。otherclass
  • オブジェクトをピクルして、実際のバージョンがotherclass存在する場所に「ネットワーク経由で送信」します。
  • リモート側でotherclassは、カスタム ピクル関数によって返されたタプルからのデータでインスタンス化されます。

Python は非常に強力です。

于 2013-01-09T16:17:18.920 に答える
5

これで解決策を発見しました。dict でコードを実行すると、python がクラスが定義されている場所を特定できないという問題があるようです。解決策は、空のモジュールを作成し、モジュール内のコードを実行してから、そのモジュールを sys.modules に追加して、Python が認識できるようにすることです。

script = """
class myClass:
    def __init__(self):
        self.name = 'apple'
        self.color = 'green'
"""

import imp, sys

moduleName = 'custom'

module = imp.new_module(moduleName)

exec script in module.__dict__

sys.modules[moduleName] = module

クラスのインスタンスをピクルおよびアンピクルできるようになりました。

import pickle
a = module.myClass()
s = pickle.dumps(a)
b = pickle.loads(s)
于 2013-01-09T20:12:46.107 に答える