Futures
*******

**Código fuente:** Lib/asyncio/futures.py, Lib/asyncio/base_futures.py

======================================================================

Los objetos *Future* se utilizan para conectar **código basado en
retrollamadas de bajo nivel** (*low-level callback-based code*) con
código *async/await* de alto nivel.


Funciones Future
================

asyncio.isfuture(obj)

   Retorna "True" si *obj* es uno de los siguientes:

   * una instancia de "asyncio.Future",

   * una instancia de "asyncio.Task",

   * un objeto tipo Future con un atributo "_asyncio_future_blocking".

   Nuevo en la versión 3.5.

asyncio.ensure_future(obj, *, loop=None)

   Retorna:

   * el argumento *obj* inalterado, si *obj* es una "Future", "Task",
     o un objeto tipo Future (esto se puede verificar con
     "isfuture()".)

   * un objeto "Task" envolviendo *obj*, si *obj* es una corrutina
     (esto se puede verificar con "iscoroutine()"); en este caso, la
     corrutina será programada por "ensure_future()".

   * un objeto "Task" que aguardará a *obj*, si *obj* es aguardable
     (esto se puede verificar con "inspect.isawaitable()".)

   Si *obj* no es ninguno de los superiores, se lanzará "TypeError".

   Importante:

     Ver también la función "create_task()", que es la forma preferida
     de crear nuevas *Tasks*.Save a reference to the result of this
     function, to avoid a task disappearing mid execution.

   Distinto en la versión 3.5.1: La función acepta cualquier objeto
   *awaitable*.

asyncio.wrap_future(future, *, loop=None)

   Envuelve un objeto "concurrent.futures.Future" en un objeto
   "asyncio.Future".


Objeto Future
=============

class asyncio.Future(*, loop=None)

   Un Future representa un resultado eventual de una operación
   asíncrona. No es seguro en hilos (*thread-safe*).

   Future es un objeto *awaitable*. Las corrutinas pueden esperar
   (*await*) a objetos Future hasta que obtengan un resultado o
   excepción, o hasta que se cancelen.

   Normalmente, los Futures se utilizan para permitir que código
   basado en retrollamadas de bajo nivel (*low-level callback-based
   code*) (por ejemplo, en protocolos implementados utilizando
   *asyncio* transports) interactúe con código *async/await* de alto
   nivel.

   Es recomendable no exponer nunca objetos Future en APIs expuestas
   al usuario, y la forma recomendada de crear un objeto Future es
   llamando a "loop.create_future()". De esta forma, implementaciones
   alternativas de bucles de eventos (*event loop*) pueden inyectar
   sus propias implementaciones optimizadas de un objeto Future.

   Distinto en la versión 3.7: Añadido soporte para el módulo
   "contextvars".

   result()

      Retorna el resultado del Future.

      Si el Future es *done* y tiene un resultado establecido por el
      método "set_result()", el valor resultante es retornado.

      Si el Future es *done* y tiene una excepción establecida por el
      método "set_exception()", este método lanzará esta excepción.

      Si un evento es *cancelled*, este método lanzará una excepción
      "CancelledError".

      Si el resultado del Future todavía no está disponible, este
      método lanzará una excepción "InvalidStateError".

   set_result(result)

      Marca el Future como *done* y establece su resultado.

      Lanza un error "InvalidStateError" si el Future ya está *done*.

   set_exception(exception)

      Marca el Future como *done* y establece una excepción.

      Lanza un error "InvalidStateError" si el Future ya está *done*.

   done()

      Retorna "True" si el Future está *done*.

      Un Future está *done* si estaba *cancelled* o si tiene un
      resultado o excepción establecidos mediante llamadas a
      "set_result()" o "set_exception()".

   cancelled()

      Retorna "True" si el Future fue *cancelled*.

      El método suele utilizarse para comprobar que un Future no es
      *cancelled* antes de establecer un resultado o excepción al
      mismo:

         if not fut.cancelled():
             fut.set_result(42)

   add_done_callback(callback, *, context=None)

      Añade una retrollamada (*callback*) a ser ejecutada cuando el
      Future es *done*.

      La retrollamada (*callback*) es llamada con el objeto Future
      como su único argumento.

      Si el Future ya es *done* cuando se llama a este método, la
      retrollamada (*callback*) es programada con "loop.call_soon()".

      Un argumento opcional de contexto, por palabra clave, permite
      especificar un "contextvars.Context" personalizado para ser
      ejecutado en la retrollamada (*callback*). El contexto actual se
      utiliza cuando no se provee un contexto (*context*).

      "functools.partial()" se puede utilizar para dar parámetros a la
      retrollamada (*callback*), por ejemplo:

         # Call 'print("Future:", fut)' when "fut" is done.
         fut.add_done_callback(
             functools.partial(print, "Future:"))

      Distinto en la versión 3.7: El parámetro de contexto (*context*)
      por palabra clave fue añadido. Ver **PEP 567** para más
      detalles.

   remove_done_callback(callback)

      Elimina la retrollamada (*callback*) de la lista de
      retrollamadas.

      Retorna el número de retrollamadas (*callbacks*) eliminadas, que
      normalmente es 1, excepto si una retrollamada fue añadida más de
      una vez.

   cancel(msg=None)

      Cancela el Future y programa retrollamadas (*callbacks*).

      Si el Future ya está *done* o *cancelled*, retorna "False". De
      lo contrario, cambia el estado del Future a *cancelled*,
      programa las retrollamadas, y retorna "True".

      Distinto en la versión 3.9: Se agregó el parámetro "msg".

   exception()

      Retorna la excepción definida en este Future.

      La excepción (o "None" si no se había establecido ninguna
      excepción) es retornada sólo si Future es *done*.

      Si un evento es *cancelled*, este método lanzará una excepción
      "CancelledError".

      Si el Future todavía no es *done*, este método lanza una
      excepción "InvalidStateError".

   get_loop()

      Retorna el bucle de eventos (*event loop*) al cual el objeto
      Future está asociado.

      Nuevo en la versión 3.7.

Este ejemplo crea un objeto Future, crea y programa una Task asíncrona
para establecer el resultado para el Future, y espera hasta que el
Future tenga un resultado:

   async def set_after(fut, delay, value):
       # Sleep for *delay* seconds.
       await asyncio.sleep(delay)

       # Set *value* as a result of *fut* Future.
       fut.set_result(value)

   async def main():
       # Get the current event loop.
       loop = asyncio.get_running_loop()

       # Create a new Future object.
       fut = loop.create_future()

       # Run "set_after()" coroutine in a parallel Task.
       # We are using the low-level "loop.create_task()" API here because
       # we already have a reference to the event loop at hand.
       # Otherwise we could have just used "asyncio.create_task()".
       loop.create_task(
           set_after(fut, 1, '... world'))

       print('hello ...')

       # Wait until *fut* has a result (1 second) and print it.
       print(await fut)

   asyncio.run(main())

Importante:

  El objeto Future fue diseñado para imitar a
  "concurrent.futures.Future". Entre las principales diferencias
  están:

  * al contrario que Futures de *asyncio*, las instancias de
    "concurrent.futures.Future" no son aguardables (*await*).

  * "asyncio.Future.result()" y "asyncio.Future.exception()" no
    aceptan el argumento *timeout*.

  * "asyncio.Future.result()" y "asyncio.Future.exception()" lanzan
    una excepción "InvalidStateError" cuando el Future no es *done*.

  * Las retrollamadas (*callbacks*) registradas con
    "asyncio.Future.add_done_callback()" no son llamadas
    inmediatamente, sino que son programadas con "loop.call_soon()".

  * *asyncio* Future no es compatible con las funciones
    "concurrent.futures.wait()" ni
    "concurrent.futures.as_completed()".

  * "asyncio.Future.cancel()" acepta un argumento opcional "msg", pero
    "concurrent.futures.cancel()" no.
