2014-04-12 5 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')) 

위의 코드는 동적 특성을보고을 산세 생존하지 않습니다. 이 코드에서는 모든 것이 예상대로 작동합니다. 그러나, 새로운 파이썬 프로세스를 사용하여 다음을 수행 :동적 특성은

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

원인 목록 APPEND없이 보고서을. 그러나 청취자를 다음과 같이 별도로 다시 설정하십시오.

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

이 다시 작동합니다.

내가 누락되었거나 처리기가 unpickling 프로세스 중에 __setstate__에 다시 설정되어야합니까?

도움을 주시면 감사하겠습니다. 이 기능은 버전 4.30의 특징이있는 창에서 Python 2.7 (32 비트) 용입니다.

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

을하지만이 report 방법에 배선하는 방법에 대한 더 이상의 정보가 없습니다 : pickletools.dis(cPickle.dumps(p)) 실행

+0

나는 hastraits souce를보고 콜백 핸들러를 저장하는 방법에 대해 유용한 것을 찾을 수 없었다. 나는 너무 참을성이 없었다. 어쨌든, 문제는 코드에있는 것이 아니라 특성에 있습니다. 나는 그것을 해키라고 생각하지만, 나는 setstate가 갈 길이라고 생각한다. __setst____은 인스턴스 dict를 인수로 받음을 기억하십시오. 핸들러를 재설정하기 전에 self .__ dict__에 지정해야합니다. – Kenny

답변

3

, 당신은 핸들러 객체가 참조되는 것을 볼 수 있습니다. 따라서 trait_handler가 제대로 피클하지 못하거나, 처음부터 절이 될 수없는 파일 핸들과 같은 임시적인 것입니다.

두 경우 모두 가장 좋은 방법은 개체를 다시 만들 때 __setstate__을 오버로드하고 이벤트 처리기를 다시 연결하는 것입니다. 이상적은 아니지만 최소한 모든 것이 객체 내에 포함되어 있습니다.

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

당신은 흥미로운 this talk Alex Gaynor did at PyCon을 찾을 수 있습니다 : 파일을 Unpickling

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 

올바르게 이벤트 핸들러를 등록합니다. 그것은 두건의 밑에 산 절이는 일의 중대한 시점으로 간다.

EDIT - 초기 응답 사용 on_trait_change - 작동 오류가 있습니다. 명확성을 위해 on_trait_event으로 다시 변경되었습니다.

0

나는 같은 문제가 있었지만 다음과 같이 돌아왔다. 이미징 조용한 큰 클래스의 일부만 피클 링하고 일부 객체는 너무 일시적으로 설정되어 있으므로 True가 설정되어 있으므로 중요하지 않으므로 절인되지 않습니다. 예를 들어

저장해야 할 대상과의 차이점. 내 LineSpectrum 클래스에서

spectrometer = Instance(SomeNiceSpectrometer) 

, 내 경우에는

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) 

을 가지고,이 완벽하게 작동 - 모든 슬라이더가 작동, 개체가 절인 된 시간에 설정된 모든 값이 다시 설정됩니다.

희망 사항은 본인 또는 동일한 문제가있는 사람에게 적합합니다. Anaconda Python 2.7.11을 얻었습니다. 모든 패키지가 업데이트되었습니다.

추신 : 나는 스레드가 오래된 것을 알고 있지만이 것을 위해 새 스레드를 열지 않으려 고합니다.

관련 문제