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

Đoạn mã trên báo cáo một đặc điểm năng động. Mọi thứ hoạt động như mong đợi trong mã này. Tuy nhiên, sử dụng một mới quá trình python và cách làm như sau:đặc điểm động không tồn tẩy

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

nguyên nhân không có báo cáo danh sách append. Tuy nhiên, hãy thiết lập lại người nghe riêng biệt như sau:

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

làm cho nó hoạt động trở lại.

Tôi có thiếu thứ gì đó hay bộ xử lý cần phải được thiết lập lại trong __setstate__ trong quá trình bỏ ghim.

Bất kỳ trợ giúp nào được đánh giá cao. Điều này là dành cho Python 2.7 (32-bit) trên các cửa sổ với các đặc điểm phiên bản 4.30.

+0

Tôi nhìn vào hastraits souce, và không thể tìm thấy bất cứ điều gì hữu ích về cách nó lưu trữ các trình xử lý gọi lại. Tôi đã quá thiếu kiên nhẫn. Dù sao, vấn đề dường như không nằm trong mã của bạn, nhưng trong các đặc điểm. Tôi tìm thấy nó hacky, nhưng tôi nghĩ rằng setstate là con đường để đi. Chỉ cần nhớ rằng __setstate__ nhận dụ dict là một đối số, mà bạn phải gán cho self .__ dict__ trước khi thiết lập lại trình xử lý. – Kenny

Trả lời

3

Chạy pickletools.dis(cPickle.dumps(p)), bạn sẽ nhìn thấy đối tượng xử lý đang được tham chiếu:

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

Nhưng không có thêm thông tin về nó như thế nào nên được chuyển đến phương pháp report. Vì vậy, hoặc trait_handler không tự mình lấy ra đúng cách, hoặc nó là một điều không lâu như một tập tin xử lý mà không thể được ngâm ở nơi đầu tiên.

Trong cả hai trường hợp, tùy chọn tốt nhất của bạn là quá tải __setstate__ và tái xử lý sự kiện khi đối tượng được tạo lại. Nó không lý tưởng, nhưng ít nhất mọi thứ đều được chứa trong đối tượng.

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 file tại đăng ký một cách chính xác các xử lý sự kiện:

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

Bạn có thể thấy this talk Alex Gaynor did at PyCon thú vị. Nó đi vào những điểm cao của cách làm việc ngâm dưới mui xe.

EDIT - phản hồi ban đầu được sử dụng on_trait_change - lỗi đánh máy xuất hiện để hoạt động. Thay đổi nó trở lại on_trait_event để rõ ràng.

0

Tôi có cùng một vấn đề nhưng đến xung quanh như thế này: Hình ảnh tôi muốn chỉ chọn một phần của một lớp học lớn yên tĩnh và một số đối tượng đã được đặt quá thoáng qua = Đúng vì vậy chúng không được ngâm vì không có gì quan trọng để tiết kiệm, ví dụ

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

Trong sự khác biệt với các đối tượng cần được lưu, ví dụ

spectrometer = Instance(SomeNiceSpectrometer) 

Trong lớp LineSpectrum của tôi, tôi có một

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) 

Trong trường hợp của tôi, điều này hoạt động hoàn hảo - tất cả các thanh trượt đang làm việc, tất cả các giá trị thiết lập tại thời điểm đối tượng đã được ngâm được thiết lập trở lại.

Hy vọng điều này phù hợp với bạn hoặc bất kỳ ai có cùng vấn đề. Có Anaconda Python 2.7.11, tất cả các gói được cập nhật.

PS: Tôi biết chủ đề cũ, nhưng không muốn mở một chủ đề mới chỉ cho việc này.

Các vấn đề liên quan