2014-04-12 12 views
7

traits_pickle_problem.py

from traits.api import HasTraits, List 
import cPickle 

class Client(HasTraits): 
    data = List 

class Person(object): 
    def __init__(self): 
     self.client = Client() 
     # dynamic handler 
     self.client.on_trait_event(self.report,'data_items') 

    def report(self,obj,name,old,new): 
     print 'client added-- ' , new.added 

if __name__ == '__main__': 
    p = Person() 
    p.client.data = [1,2,3] 
    p.client.data.append(10) 
    cPickle.dump(p,open('testTraits.pkl','wb')) 

Powyższy kod informuje dynamiczną cechę. Wszystko działa zgodnie z oczekiwaniami w tym kodzie. Jednak stosując nowy proces Python i wykonując następujące czynności:dynamiczne cechy nie przetrwać trawieniu

>>> from traits_pickle_problem import Person, Client            
>>> p=cPickle.load(open('testTraits.pkl','rb'))             
>>> p.client.data.append(1000) 

przyczyn Nie Zgłoś z listy dopisywania. Jednak ponowne ustanowienie słuchacza osobno:

>>> p.client.on_trait_event(p.report,'data_items')             
>>> p.client.data.append(1000)                  
client added-- [1000]  

sprawia, że ​​działa ponownie.

Czy czegoś brakuje lub czy należy ponownie ustanowić przewodnik w __setstate__ podczas procesu rozpylania.

Każda pomoc doceniona. Dotyczy to wersji Python 2.7 (32-bit) w oknach o cechach wersji 4.30.

+0

Spojrzałem na sakiewkę hastraits i nie mogłem znaleźć nic użytecznego o tym, jak przechowuje ona procedury obsługi wywołań zwrotnych. Byłem zbyt niecierpliwy. W każdym razie problem nie leży w twoim kodzie, ale w cechach. Uważam, że jest to odjazdowe, ale myślę, że droga na szczyt to droga. Pamiętaj tylko, że __setstate__ odbiera dict instancji jako argument, który musisz przypisać do self .__ dict__ przed przywróceniem obsługi. – Kenny

Odpowiedz

3

Running pickletools.dis(cPickle.dumps(p)) można zobaczyć obiekt obsługi którego odwołuje:

... 
    213: c  GLOBAL  'traits.trait_handlers TraitListObject' 
    ... 

Ale nie ma dalszych informacji na temat jak to powinno być podłączone do sposobu report. Tak więc albo trait_handler nie pobiera się poprawnie, albo jest to efemeryczne narzędzie, takie jak uchwyt pliku, którego nie można usunąć.

W obu przypadkach najlepszą opcją jest przeciążenie __setstate__ i ponowne połączenie procedury obsługi zdarzenia po ponownym utworzeniu obiektu. Nie jest idealny, ale przynajmniej wszystko jest zawarte w obiekcie.

class Person(object): 
    def __init__(self): 
     self.client = Client() 
     # dynamic handler 
     self.client.on_trait_event(self.report, 'data_items') 

    def __setstate__(self, d): 
     self.client = d['client'] 
     self.client.on_trait_event(self.report, 'data_items') 

    def report(self, obj, name, old, new): 
     print 'client added-- ', new.added 

Unpickling plik teraz poprawnie rejestruje obsługi zdarzenia:

p=cPickle.load(open('testTraits.pkl','rb')) 
p.client.data.append(1000) 
>>> client added-- [1000] 

może znaleźć this talk Alex Gaynor did at PyCon ciekawego. Wpływa na najwyższy punkt pracy marynarskiej pod maską.

EDYCJA - początkowa odpowiedź używana on_trait_change - literówka, która wydaje się działać. Zmieniono go z powrotem na on_trait_event dla jasności.

0

Miałem ten sam problem, ale pojawiłem się w ten sposób: Obrazowanie Chcę wybrać tylko części cichej, wielkiej klasy, a niektóre z obiektów zostały ustawione tak przejściowo = Prawdziwe, że nie są marynowane, ponieważ nie ma w nich nic ważnego zapisać, np

class LineSpectrum(HasTraits): 
    andor_cam = Instance(ANDORiKonM, transient=True) 

W odróżnieniu od obiektów, które powinny zostać zapisane, np.

spectrometer = Instance(SomeNiceSpectrometer) 

W mojej klasie LineSpectrum mam

def __init__(self, f): 
    super(LineSpectrum, self).__init__() 
    self.load_spectrum(f) 

def __setstate__(self, state): # FUCKING WORKING! 
    print("LineSpectrum: __setstate__ with super(...) call") 
    self.__dict__.update(state) 
    super(LineSpectrum, self).__init__() # this has to be done, otherwise pickled sliders won't work, also first update __dict__! 
    self.from_pickle = True # is not needed by traits, need it for myself 
    self.andor_cam = ANDORiKonM(self.filename) 
    self.load_spectrum(self.filename) 

w moim przypadku, to działa doskonale - wszystkie suwaki działają, wszystkie wartości określone w czasie, gdy obiekt został marynowanych są ustawione z powrotem.

Mam nadzieję, że działa to dla Ciebie lub każdego, kto ma ten sam problem. Otrzymałem Anaconda Python 2.7.11, wszystkie pakiety zostały zaktualizowane.

PS: Wiem, że wątek jest stary, ale nie chciał otwierać nowego tylko w tym celu.