2016-04-06 5 views
0

私は最初に使用した後にキャッシュされるオブジェクトを持っています。私はcPickleモジュールを使ってこれを行います。モジュールが既にキャッシュされている場合、次回(別のプロセスで)オブジェクトをインスタンス化しようとすると、キャッシュされたオブジェクトを使用したいと思います。以下の私の基本的な構造です:Xクラスの__new__メソッドのX型のオブジェクトのピックを解除すると、unpickleオブジェクトを返すときに__init__が呼び出されます。なぜですか?

import cPickle 
class Test(object): 
    def __new__(cls, name): 
     if name == 'john': 
      print "using cached object" 
      with open("cp.p", "rb") as f: 
       obj = cPickle.load(f) 
       print "object unpickled" 
       return obj 
     else: 
      print "using new object" 
      return super(Test, cls).__new__(cls, name) 
    def __init__(self, name): 
     print "calling __init__" 
     self.name = name 
     with open("cp.p", "wb") as f: 
      cPickle.dump(self, f) 

問題は、私は__new__方法でキャッシュされたオブジェクトをunpickle化するとき、それは__init__を呼び出して、すべてを再初期化していることです。興味深いことに、__init__は、unpickleの後ではなく、unpickleされたオブジェクトが返されたときのように呼び出されます。私はこれを示すprintステートメントを追加しました( "オブジェクトunpickled")。

私は__init__に次のチェックを追加することにより、ハックの回避策があります。

intiailzed = False 
... 
... 
def __init__(self, name): 
    if not self.intialized: 
     self.initialized = True 
     # Rest of the __init__ here 

と同様に初期化と呼ばれるクラスの属性を、これは明らかに理想的ではありません。

__init__メソッドを抑制する方法についての洞察(またはなぜそれが全く呼び出されているのか)を理解できます。 Test.__new__(Test, name)から返さunpickle化オブジェクトはTestのインスタンスであるので、その__init__

obj = Test.__new__(Test, name) 
if isinstance(obj, Test): 
    obj.__init__(name) 

編集:このような

class Test(object): 
    def __new__(cls, name=None): 
     print "calling __new__" 
     if name == 'john': 
      print "using cached object" 
      with open("cp.p", "rb") as f: 
       obj = cPickle.load(f) 
      print "object unpickled" 
      return obj 
     else: 
      print "using new object" 
      obj = super(Test, cls).__new__(cls, name) 
      obj.initialize(name) 
      return obj 

    def __init__(self, name): 
     pass 

    def initialize(self, name): 
     print "calling __init__" 
     self.name = name 
     with open("cp.p", "wb") as f: 
      cPickle.dump(self, f) 
+0

["__new __()がclsのインスタンスを返す場合は、新しいインスタンスの__init __()メソッドが呼び出されます"](https://docs.python.org/2/reference/datamodel.html) #object .__ new__) – unutbu

+1

[Python 2.2で統一されている型とクラス](https://www.python.org/download/releases/2.2.3/descrintro/#__new__)で、 "不変型にはダミー' __init__ '、mutable型はダミー' __new__'を持っています。 "正当な理由がないかぎり、あなたのクラスは同じパターンに従うべきです。 – unutbu

+0

これは、私が実際に自分のポイントをもっと簡単に得るために単純に一般化したものです。条件は大きく異なります。しかし、ヒントをお寄せいただきありがとうございます。私の条件が満たされ、ファイルが存在しないかどうかを検討するのは、おそらく悪いことではありませんが、失敗するようにしたいと思います。 –

答えて

2

obj = Test(name)作品:ここでのフィードバックに基づいては、私の新しい提案されたソリューションでありますメソッドが呼び出されます。オブジェクトがsuper(Test, cls).__new__か、unpicklingかどうかは関係ありません。

このような問題を回避するには、__new__をオーバーライドするクラスは、完全に初期化されたオブジェクトを__new__から返し、__init__を定義しないでください。それらのサブクラスもこの規則に従うべきです。

+0

私はあなたの提案に基づいて解決策を追加しました。それは私がそれをしたい方法を動作させるようです。 –

+0

@ J.Doe:それはうまくいきますが、私は '' __init__'を呼び出すという初期化をしていません。 – user2357112

+0

助けてくれてありがとう、私は急いですべてを 'initialize'にコピーしました。 –

関連する問題