动态特性不能在酸洗中存活

时间:2014-04-12 16:37:07

标签: python traits pickle

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'))

以上代码报告了一个动态特征。一切都在此代码中按预期工作。但是,使用 new python进程并执行以下操作:

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

导致列表追加无报告。但是,分别重新建立监听器如下:

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

让它再次运作。

我是否遗漏了某些内容,或者在解除排版过程中是否需要在__setstate__中重新建立处理程序。

任何帮助表示赞赏。这适用于具有特征版本4.30的Windows上的Python 2.7(32位)。

2 个答案:

答案 0 :(得分:3)

运行pickletools.dis(cPickle.dumps(p)),您可以看到被引用的处理程序对象:

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

但是没有关于如何连接到report方法的进一步信息。所以要么trait_handler没有正确地解决它自己,要么它是一个短暂的东西,就像文件句柄一样,不能在第一时间被腌制。

在任何一种情况下,最好的选择是重载__setstate__并在重新创建对象时重新连接事件处理程序。它并不理想,但至少一切都包含在对象中。

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

现在正在取消文件正确注册事件处理程序:

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

您可能会发现this talk Alex Gaynor did at PyCon很有趣。它进入了引擎盖下的酸洗工作的高潮。

编辑 - 使用的初始回复on_trait_change - 似乎有效的拼写错误。为清楚起见,将其更改回on_trait_event

答案 1 :(得分:0)

我遇到了同样的问题但却出现了这样的问题:成像我想只腌制一个安静的大类的部分而且一些物体已被设置为如此瞬态=真,所以他们没有被腌制,因为没有什么保存很重要,例如

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

与应保存的对象不同,例如

spectrometer = Instance(SomeNiceSpectrometer)

在我的LineSpectrum课程中,我有一个

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

def __setstate__(self, state):  # 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,所有软件包都已更新。

PS:我知道线程已经过时了,但是并不想为此开一个新线程。

相关问题