defer.execute en efecto, ejecutar la función de un modo de bloqueo, en el mismo hilo y que son correctas en que defer.execute(f, args, kwargs)
hace lo mismo que defer.succeed(f(*args, **kwargs))
excepto que defer.execute
volverá una devolución de llamada que ha tenido el errback despedido si la función f arroja una excepción. Mientras tanto, en su ejemplo diferido, si la función arrojara una excepción, se propagaría hacia afuera, lo que puede no ser deseable.
Para facilitar la comprensión, sólo voy a pegar la fuente de defer.execute aquí:
def execute(callable, *args, **kw):
"""Create a deferred from a callable and arguments.
Call the given function with the given arguments. Return a deferred which
has been fired with its callback as the result of that invocation or its
errback with a Failure for the exception thrown.
"""
try:
result = callable(*args, **kw)
except:
return fail()
else:
return succeed(result)
En otras palabras, defer.execute
es sólo un atajo para tomar el resultado de una función de bloqueo como diferidos, que se puede luego agrega callbacks/errbacks a. Las devoluciones de llamada se dispararán con semántica de encadenamiento normal. Parece un poco loco, pero Deferreds puede 'disparar' antes de agregar callbacks y las devoluciones de llamada seguirán siendo llamadas.
Así que para responder a su pregunta, Por qué es útil? Bueno, defer.execute
es útil tanto para probar/burlarse como para simplemente integrar una API asíncrona con código síncrono.
También es útil defer.maybeDeferred
que llama a la función y luego si la función ya devuelve un aplazado simplemente lo devuelve, de lo contrario funciona de manera similar a defer.execute
. Esto es útil para cuando se escribe una API que espera que un llamable que, cuando se llama, le otorgue un aplazado, y también se desee poder aceptar funciones de bloqueo normales.
Por ejemplo, supongamos que tiene una aplicación que ha buscado páginas e hizo cosas con ella. Y, por alguna razón, necesitó ejecutar esto de forma sincrónica para un caso de uso específico, como en una secuencia de comandos crontab de una sola toma, o en respuesta a una solicitud en una aplicación WSGI, pero conservando la misma base de código. Si el código se veía así, se podría hacer:
from twisted.internet import defer
from twisted.web.client import getPage
def process_feed(url, getter=getPage):
d = defer.maybeDeferred(getter, url)
d.addCallback(_process_feed)
def _process_feed(result):
pass # do something with result here
Para ejecutar esto en un contexto sincrónico, sin el reactor, sólo podía pasar una función captador alternativo, así:
from urllib2 import urlopen
def synchronous_getter(url):
resp = urlopen(url)
result = resp.read()
resp.close()
return result
+ 1 para explicar defer.maybeDeferred –