Pregunta

Tengo una máquina de estado definida por el usuario en Twisted. El usuario puede definir los manejadores para diferentes cambios de estado, que implemento utilizando un retorcido diferido a los que les dejo agregar devoluciones de llamada. Cada vez que me muevo de un estado a otro, simplemente disparo el apropiado apropiado.

Uno de los requisitos del proyecto es la capacidad de guardar esta máquina de estado en el disco, junto con todas sus devoluciones de llamada. Pensé que podría simplemente encurtir la máquina de estado y terminaría, pero obtengo un pickleerror cuando trato de serializar las funciones definidas por el usuario.

¿Alguien sabe de una forma de serializar funciones? El error se reproduce en la siguiente muestra del código:

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)

Esta última línea da el siguiente 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

¿Hay alguna solución para esto? ¿Quizás necesito restringir los tipos de funciones que los usuarios pueden agregar como devoluciones de llamada?

Gracias,
Jonathan

¿Fue útil?

Solución

No intentes encurtir diferidos. No es compatible con Twisted. Incluso si logras construir algo que parece funcionar (y no es enteramente imposible), una versión posterior de Twisted podría romper todo su estado guardado.

Los diferidos son para controlar el flujo de eventos a través de su código. No son para almacenar el estado de aplicación. Si desea persistir en su estado de solicitud, separarlo de cualquier aplazamiento y serializar sólo eso.

Cuando hace esto, probablemente también desee evitar usar Pickle para el formato de serialización. Pickle no es una buena forma de almacenar datos. Es un formato de alto complejo que es muy sensible a los cambios en las versiones de Python y las versiones de la biblioteca. No tiene medios para definir un esquema, por lo que nunca puede estar realmente seguro de lo que está serializando o lo que ha serializado. Es muy difícil inspeccionar un encurtido por separado de cargarlo, por lo que si alguna vez se rompe (como lo hará si decide cambiar el nombre de una clase de la que tiene instancias en escabeche), recuperar los datos es una molestia importante.

Otros consejos

Reemplace las funciones de Foo/Bar con una instancia de clase llamable:

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)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top