example - tornado python mac
Diferencia en tornado.gen.engine v/s tornado.gen.coroutine (1)
Pasando por la documentación tornado.gen alguien me puede ayudar a entender la diferencia exacta entre tornado.gen.coroutine y tornado.gen.engine
Como dice la documentación del tornado para gen.engine
:
Este decorador es similar a coroutine, excepto que no devuelve un futuro y el argumento de devolución de llamada no se trata de manera especial.
Y como dice la documentación de gen.coroutine
Desde la perspectiva de la persona que llama, @ gen.coroutine es similar a la combinación de @return_future y @ gen.engine.
gen.engine
es básicamente una versión más antigua, menos aerodinámica de lo que hace coroutine. Si está escribiendo un código nuevo, debe seguir los consejos de la documentación y siempre usar tornado.gen.coroutine
.
Es bastante evidente si mira el código para ambas funciones (con la documentación eliminada).
motor:
def engine(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
runner = None
def handle_exception(typ, value, tb):
if runner is not None:
return runner.handle_exception(typ, value, tb)
return False
with ExceptionStackContext(handle_exception) as deactivate:
try:
result = func(*args, **kwargs)
except (Return, StopIteration) as e:
result = getattr(e, ''value'', None)
else:
if isinstance(result, types.GeneratorType):
def final_callback(value):
if value is not None:
raise ReturnValueIgnoredError(
"@gen.engine functions cannot return values: "
"%r" % (value,))
assert value is None
deactivate()
runner = Runner(result, final_callback)
runner.run()
return
if result is not None:
raise ReturnValueIgnoredError(
"@gen.engine functions cannot return values: %r" %
(result,))
deactivate()
# no yield, so we''re done
return wrapper
coroutine:
def coroutine(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
runner = None
future = TracebackFuture()
if ''callback'' in kwargs:
callback = kwargs.pop(''callback'')
IOLoop.current().add_future(
future, lambda future: callback(future.result()))
def handle_exception(typ, value, tb):
try:
if runner is not None and runner.handle_exception(typ, value, tb):
return True
except Exception:
typ, value, tb = sys.exc_info()
future.set_exc_info((typ, value, tb))
return True
with ExceptionStackContext(handle_exception) as deactivate:
try:
result = func(*args, **kwargs)
except (Return, StopIteration) as e:
result = getattr(e, ''value'', None)
except Exception:
deactivate()
future.set_exc_info(sys.exc_info())
return future
else:
if isinstance(result, types.GeneratorType):
def final_callback(value):
deactivate()
future.set_result(value)
runner = Runner(result, final_callback)
runner.run()
return future
deactivate()
future.set_result(result)
return future
return wrapper
Ambas son probablemente bastante difíciles de entender a primera vista. Pero aún así, es obvio que el código es muy similar, excepto que @gen.coroutine
tiene un manejo especial del kwarg de callback
de callback
, y crea / devuelve un Future
. @gen.engine
tiene un código que específicamente arroja un error si intentas devolver algo de él, en lugar de ponerlo en el Future
.