Wie man eine Rückrufkette einweiht
Frage
Ich habe eine benutzerdefinierte Statusmaschine in Twisted. Der Benutzer kann Handler für unterschiedliche Zustandsänderungen definieren, die ich mit einem verdrehten aufgeschobenen Aufschub implementieren kann, zu dem ich sie zurück -Rückrufe hinzufügen kann. Immer wenn ich von einem Zustand in einen anderen wechsle, feuere ich einfach die entsprechende Aufschiebung ab.
Eine der Projektanforderungen ist die Möglichkeit, diese Zustandsmaschine zusammen mit allen Rückrufen zu retten. Ich dachte, ich könnte einfach die Statusmaschine übersagen und ich würde fertig sein, aber ich bekomme einen PickleError, wenn ich versuche, benutzerdefinierte Funktionen zu serialisieren.
Kennt jemand eine Möglichkeit, Funktionen zu serialisieren? Der Fehler wird in der folgenden Code -Probe reproduziert:
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)
Diese letzte Zeile gibt den folgenden Fehler:
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
Gibt es Lösungen dafür? Vielleicht muss ich die Arten von Funktionen einschränken, die Benutzer als Rückrufe hinzufügen können?
Vielen Dank,
Jonathan
Lösung
Versuchen Sie nicht, Aufschiebungen zu überlegen. Es wird nicht von Twisted unterstützt. Auch wenn Sie es schaffen, etwas zu konstruieren, das zu funktionieren scheint (und es ist nicht völlig Unmöglich), eine spätere Veröffentlichung von Twisted könnte Ihren gesamten gespeicherten Zustand brechen.
Aufschubs dient zur Steuerung des Ereignisflusss über Ihren Code. Sie sind nicht für die Aufbewahrung des Anwendungszustands. Wenn Sie Ihren Bewerbungszustand bestehen möchten, trennen Sie ihn von Aufstiegsvorschriften und Serialize nur es.
Wenn Sie dies tun, möchten Sie wahrscheinlich auch die Verwendung von Gurke für das Serialisierungsformat vermeiden. Pickle ist keine gute Möglichkeit, Daten zu speichern. Es ist ein hochkomplexes Format, das sehr empfindlich gegenüber Änderungen in Python -Versionen und Bibliotheksversionen ist. Es hat keine Mittel, um ein Schema zu definieren, sodass Sie nie wirklich sicher sein können, was Sie serialisieren oder was Sie serialisiert haben. Es ist sehr schwierig, eine Gurke getrennt vom Laden zu inspizieren. Wenn sie also jemals bricht (wie es so wird, wenn Sie sich entscheiden, eine Klasse umzubenennen, die Sie eingelegt haben), ist die Wiederherstellung der Daten ein großer Aufwand.
Andere Tipps
Ersetzen Sie die Foo/Bar -Funktionen durch eine Callable -Klasse -Instanz:
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)