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

rec*_*ner 7 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'))
Run Code Online (Sandbox Code Playgroud)

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

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

导致没有列表的报告追加.但是,分别重新建立监听器如下:

>>> p.client.on_trait_event(p.report,'data_items')                                                
>>> p.client.data.append(1000)                                                                    
client added--  [1000]     
Run Code Online (Sandbox Code Playgroud)

使它再次工作.

我是否遗漏了某些东西,或者__setstate__在拆除过程中是否需要重新建立处理程序.

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

dmc*_*lan 3

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

  ...
  213: c        GLOBAL     'traits.trait_handlers TraitListObject'
  ...
Run Code Online (Sandbox Code Playgroud)

但没有关于如何将其连接到该report方法的更多信息。因此,要么trait_handler没有正确地pickle自己,要么它是一个短暂的东西,比如文件句柄,一开始就无法pickle。

无论哪种情况,最好的选择是__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
Run Code Online (Sandbox Code Playgroud)

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

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

您可能会发现Alex Gaynor 在 PyCon 上所做的演讲很有趣。它深入探讨了酸洗在幕后如何工作的要点。

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