rec*_*ner 7 python traits pickle
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位).
运行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。