2016-04-06 48 views
0

İlk kullanımdan sonra önbelleğe alınacak bir nesnem var. Bunu cPickle modülünü kullanarak yapacağım. Modül önbelleğe alınmışsa, nesneyi bir dahaki seferde (başka bir işlemde) başlatmaya çalıştığımda, önbelleğe alınmış nesneyi kullanmak istiyorum. Aşağıdaki benim temel yapıdır:X sınıfının __new__ yöntemindeki X türünde unpickling nesnesi, ayrılmamış nesneyi döndürme konusunda __init__ çağrısında bulunur, neden?

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) 

Sorun __new__ yönteminde önbelleğe nesne unpickle zaman __init__ çağırır ve her şeyi reinitializes olmasıdır. İlginç bir şekilde, __init__ unpickling'den sonra değil, unpickled nesnesi döndüğünde çağrılır. Bunu gösteren bir "print ifadesi" ekledim ("object unpickled").

Ben __init__ aşağıdaki onay ekleyerek hacky geçici çözüm vardır:

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

yanı sıra başlatıldı denilen class özelliği, ancak bu besbelli ideal değildir.

__init__ yöntemini (ya da neden çağrıldığını) nasıl bastırılacağına ilişkin herhangi bir fikir takdir edilecektir.

Düzenleme: Böyle

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

Dokümanlar, ["__new __(), cls örneğini döndürürse, yeni örneğin __init __() yöntemi çağrılır"] (https://docs.python.org/2/reference/datamodel.html #object .__ new__) – unutbu

+1

Başına [Python 2.2'deki türleri ve sınıfları birleştirmek] (https://www.python.org/download/releases/2.2.3/descrintro/#__new__), "değişmez türlerin bir kukla var" __init__ ', değişken tiplerde bir' __new__' kukla var. ' İyi bir nedeniniz olmadıkça (ve hiçbirini bilmiyorum), sınıflarınız da aynı düzeni izlemelidir. – unutbu

+0

Bu, aslında daha kolay noktayı elde etmek için sahip olduğum şeyin basitleştirilmiş bir genellemesiydi, koşullar çok farklı. Ancak bahşiş için teşekkürler, muhtemelen kötü bir şey olmamasına rağmen benim durumumun yerine getirilip getirilmediğini ve dosyanın mevcut olmadığını düşünmeme izin vermem. –

cevap

2

obj = Test(name) işleri: SIRKESIZ nesne Test.__new__(Test, name) dönen yana

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

Test bir örneğidir, onun __init__ geri bildirime dayanarak burada benim yeni önerilen çözüm yöntem denir. Nesnenin super(Test, cls).__new__'dan gelip gelmemesi veya çıkarılmaması fark etmez.

Bu gibi sorunlardan kaçınmak için, __new__'u geçersiz kılan sınıflar genellikle tamamen başlatılmış nesneleri __new__'dan döndürmeli ve __init__ tanımlamamalıdır. Alt sınıfları da bu kuralı takip etmelidir.

+0

Önerinize dayalı bir çözüm ekledim, bir göz atabilir ve bana bir ücret verebilir misiniz? İstediğim gibi çalışıyor. –

+0

@ J.Doe: Evet, işe yaramazsa da, 'initialize' denemese de' __init__'' diyerek. – user2357112

+0

Yardımlarınız için teşekkür ederim, ve ben her şeyi aceleyle 'initialize' haline getirdim, normalde bu baskı ifadelerine bile sahip olmayacağım. –