如何pickle回调链
我在 Twisted 中有一个用户定义的状态机。用户可以为不同的状态更改定义处理程序,我通过使用 Twisted 延迟来实现,我让他们添加回调。每当我从一种状态转移到另一种状态时,我只需触发适当的延迟。
项目要求之一是能够将此状态机及其所有回调保存到磁盘。我以为我可以简单地pickle状态机就可以完成,但是当我尝试序列化用户定义的函数时,我得到了一个PickleError。
有人知道序列化函数的方法吗?下面的代码示例中重现了该错误:
import pickle
from twisted.internet.utils import defer
def foo(*args):
def bar():
print args
return bar
d = defer.Deferred()
d.addCallback(foo("Hello", "world"))
pickle.dumps(d)
最后一行给出了以下错误:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.5/pickle.py", line 1366, in dumps
Pickler(file, protocol).dump(obj)
File "/usr/lib/python2.5/pickle.py", line 224, in dump
self.save(obj)
File "/usr/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.5/pickle.py", line 725, in save_inst
save(stuff)
File "/usr/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.5/pickle.py", line 649, in save_dict
self._batch_setitems(obj.iteritems())
File "/usr/lib/python2.5/pickle.py", line 663, in _batch_setitems
save(v)
File "/usr/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.5/pickle.py", line 600, in save_list
self._batch_appends(iter(obj))
File "/usr/lib/python2.5/pickle.py", line 615, in _batch_appends
save(x)
File "/usr/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.5/pickle.py", line 562, in save_tuple
save(element)
File "/usr/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.5/pickle.py", line 562, in save_tuple
save(element)
File "/usr/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.5/pickle.py", line 748, in save_global
(obj, module, name))
pickle.PicklingError: Can't pickle <function bar at 0xb753fe2c>: it's not found as __main__.bar
对此有任何解决方案吗?也许我需要限制用户可以添加为回调的函数类型?
谢谢,
乔纳森
I have a user-defined state machine in Twisted. The user can define handlers for different state changes, which I implement by using a Twisted deferred that I let them add callbacks to. Whenever I move from one state to another, I simply fire the appropriate deferred.
One of the project requirements is the ability to save this state machine to disk, along with all its callbacks. I thought I could simply pickle the state machine and I'd be done, but I get a PickleError when I try to serialize user-defined functions.
Does anybody know of a way to serialize functions? The error is reproduced in the below code sample:
import pickle
from twisted.internet.utils import defer
def foo(*args):
def bar():
print args
return bar
d = defer.Deferred()
d.addCallback(foo("Hello", "world"))
pickle.dumps(d)
This last line gives the following error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.5/pickle.py", line 1366, in dumps
Pickler(file, protocol).dump(obj)
File "/usr/lib/python2.5/pickle.py", line 224, in dump
self.save(obj)
File "/usr/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.5/pickle.py", line 725, in save_inst
save(stuff)
File "/usr/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.5/pickle.py", line 649, in save_dict
self._batch_setitems(obj.iteritems())
File "/usr/lib/python2.5/pickle.py", line 663, in _batch_setitems
save(v)
File "/usr/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.5/pickle.py", line 600, in save_list
self._batch_appends(iter(obj))
File "/usr/lib/python2.5/pickle.py", line 615, in _batch_appends
save(x)
File "/usr/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.5/pickle.py", line 562, in save_tuple
save(element)
File "/usr/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.5/pickle.py", line 562, in save_tuple
save(element)
File "/usr/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.5/pickle.py", line 748, in save_global
(obj, module, name))
pickle.PicklingError: Can't pickle <function bar at 0xb753fe2c>: it's not found as __main__.bar
Are there any solutions to this? Maybe I need to restrict the types of functions that users can add as callbacks?
Thanks,
Jonathan
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不要试图腌制 Deferreds。 Twisted 不支持它。即使您设法构建出一些看起来可行的东西(并且这并非完全不可能),Twisted 的后续版本也可能会破坏您所有已保存的状态。
延迟用于控制代码中的事件流。它们不用于存储应用程序状态。如果您想保留应用程序状态,请将其与任何 Deferreds 分开并仅对其进行序列化。
当您执行此操作时,您可能还希望避免使用 pickle 作为序列化格式。 Pickle 不是存储数据的好方法。它是一种高度复杂的格式,对Python版本和库版本的变化非常敏感。它无法定义模式,因此您永远无法真正确定正在序列化的内容或已序列化的内容。单独检查 pickle 和加载它是非常困难的,所以如果它损坏了(如果你决定重命名一个已经 pickle 实例的类,就会发生这种情况),恢复数据是一个很大的麻烦。
Don't try to pickle Deferreds. It's not supported by Twisted. Even if you manage to construct something that seems to work (and it's not entirely impossible), a later release of Twisted might break all of your saved state.
Deferreds are for controlling the flow of events through your code. They're not for storing application state. If you want to persist your application state, separate it from any Deferreds and serialize just it.
When you do this, you probably also want to avoid using pickle for the serialization format. Pickle is not a good way to store data. It is a high complex format which is very sensitive to changes in Python versions and library versions. It has no means to define a schema, so you can never really be sure what you're serializing or what you have serialized. It is very difficult to inspect a pickle separately from loading it, so if it ever breaks (as it will if you decide to rename a class which you have pickled instances of), recovering the data is a major hassle.
将 foo/bar 函数替换为可调用的类实例:
Replace the foo/bar functions with a callable class instance: