如何pickle回调链

发布于 2024-10-14 22:57:03 字数 2303 浏览 5 评论 0原文

我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

随遇而安 2024-10-21 22:57:03

不要试图腌制 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.

献世佛 2024-10-21 22:57:03

将 foo/bar 函数替换为可调用的类实例:

class foo(object):
    def __init__(self, *args):
        self.args = args
    def __call__(self):
        print self.args

d = defer.Deferred()
d.addCallback(foo("Hello", "world"))
pickle.dumps(d)

Replace the foo/bar functions with a callable class instance:

class foo(object):
    def __init__(self, *args):
        self.args = args
    def __call__(self):
        print self.args

d = defer.Deferred()
d.addCallback(foo("Hello", "world"))
pickle.dumps(d)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文