2013-01-09 10 views
9

私はクラス定義するスクリプトがある場合:別の名前空間(Python)にクラスが存在するオブジェクトを解除する方法はありますか?

script = """ 

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

""" 

をして、独自の名前空間の辞書では、このスクリプトがexec:

NS = {} 
exec script in NS 

をして、クラスのインスタンスを作成し、それを酸洗い:

a = NS['myClass']() 

import pickle 

save = pickle.dumps(a) 

は今、私はそれをunpickle化しようとした場合:

私はエラー

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

を得る10

私はPythonがどこオブジェクトを再構築するために、MyClassのを見つけるために知っていないので、これは動作しないことを収集します。しかし、myClassはNS辞書に存在します。 Pickleに、ロードされているオブジェクトのクラスを見つける場所を教える方法はありますか?

答えて

2

解決策を発見しました。問題は、ディクテーションでコードを実行すると、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 

今ではクラスのインスタンスを酸洗し、unpickle化することが可能である:

import pickle 
a = module.myClass() 
s = pickle.dumps(a) 
b = pickle.loads(s) 
3

実際にはさらに進んで、目的のタイプにオブジェクトを再構成できます。

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 

基本的な考え方は、あなたがその復興はそれがもともとあったものとは別のクラスのインスタンス化の原因となる一種の「トロイの木馬」、にあなたのクラスを詰めることです。

は問題ではない酸洗い側のものには何が入っているか。重要なことは、「宛先」クラスと同じモジュールパスに存在することです。pickleは、モジュール名の文字列表現を直列化されたストリームに入れるだけです。だから、

、詳細に上記のコードで何が起こっているかを打破するには:

  • 我々はmyClassのカスタムPicklerさんを登録します。これは、copy_regまたは__reduce_ex__機能を介して行うことができます。
  • 当社のカスタムPicklerさんはダミーである(「otherclassのインスタンスとしてこれを酸洗い」と言う。ピクルスに入ること、すべてのモジュールがあるので、あなたはは、酸洗側otherclassの「本当」の内容を必要としません/クラス名)。
  • 私たちはオブジェクトをピックルし、otherclassの実際のバージョンが存在する場所に「ワイヤを渡って送ってください」。
  • リモート側では、カスタムpickling関数によって返されたタプルのデータでotherclassがインスタンス化されます。

Pythonはかなり強力です!

+0

これはすべての非常にきれいですが、それはどのように元の質問に答えるのでしょうか? –

+1

@JohnYクラスをunpickleを、unpicklerの名前空間から任意のクラスのインスタンスにすることができます。 'myClass'を' foomodule.myClass'としてunpickleに設定してから、 'pickle.loads'を呼び出す前に' foomodule.myClass = NS ['myClass'] 'と言ってください。 – Borealid

関連する問題