3

Twisted にユーザー定義のステート マシンがあります。ユーザーはさまざまな状態変化のハンドラーを定義できます。これは、私がコールバックを追加できる Twisted deferred を使用して実装します。ある状態から別の状態に移動するときはいつでも、適切な deferred を起動するだけです。

プロジェクトの要件の 1 つは、このステート マシンをすべてのコールバックと共にディスクに保存する機能です。単純にステート マシンをピクルすれば完了だと思っていましたが、ユーザー定義関数をシリアル化しようとすると 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

これに対する解決策はありますか?ユーザーがコールバックとして追加できる関数の種類を制限する必要があるのでしょうか?

ありがとう、
ジョナサン

4

2 に答える 2

2

延期を漬けようとしないでください。Twistedではサポートされていません。うまくいくように見えるものを構築できたとしても(そしてそれは完全に不可能ではありません)、Twistedのその後のリリースでは、保存された状態がすべて壊れる可能性があります。

延期は、コード内のイベントのフローを制御するためのものです。アプリケーションの状態を保存するためのものではありません。アプリケーションの状態を保持したい場合は、それをDeferredから分離し、それだけをシリアル化します。

これを行うときは、シリアル化形式にピクルスを使用することも避けたいと思うでしょう。Pickleはデータを保存するための良い方法ではありません。これは非常に複雑な形式であり、Pythonバージョンとライブラリバージョンの変更に非常に敏感です。スキーマを定義する手段がないため、何をシリアル化しているのか、何をシリアル化しているのかを実際に確認することはできません。ピクルスをロードするのとは別に検査することは非常に難しいため、ピクルスが壊れた場合(インスタンスをピクルスにしたクラスの名前を変更する場合のように)、データの回復は大きな手間です。

于 2011-01-28T18:21:27.047 に答える
0

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)
于 2011-01-28T17:53:14.363 に答える