# Futurs

Code source : Lib/asyncio/futures.py, Lib/asyncio/base_futures.py

Les objets Future sont utilisés comme passerelles entre du code bas niveau basé sur des fonctions de rappel et du code haut niveau utilisant async et await.

## Fonctions pour Future

`asyncio.``isfuture`(obj)

  Renvoie `True` si obj est soit :

  - une instance de `asyncio.Future` ;

  - une instance de `asyncio.Task` ;

  - un objet se comportant comme Future et possédant un attribut `_asyncio_future_blocking`.

  Nouveau dans la version 3.5.

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

  Renvoie :

  - l'objet obj tel quel si c'est un objet `Future`, `Task` ou se comportant comme un Future. `isfuture()` est utilisée pour le test ;

  - un objet `Task` encapsulant obj si ce dernier est une coroutine (`iscoroutine()` est utilisée pour le test). Dans ce cas, l’exécution de la coroutine sera planifiée par `ensure_future()` ;

  - un objet `Task` qui attendra (await) obj si ce dernier peut être attendu (awaitable). `iscoroutine()` est utilisée pour le test.

  Si obj ne correspond à aucun des critères ci-dessus, une exception `TypeError` est levée.

  Important

  Voir aussi la fonction `create_task()` qui est la manière privilégiée pour créer des nouvelles tâches.

  Modifié dans la version 3.5.1: La fonction accepte n'importe quel objet awaitable.

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

  Encapsule un objet `concurrent.futures.Future` dans un objet `asyncio.Future`.

## Objet Future

class `asyncio.``Future`(*, loop=None)

  Un Future représente le résultat final d'une opération asynchrone. Il n'est pas conçu pour pouvoir être utilisé par plusieurs fils d'exécution.

  Future is an awaitable object. Coroutines can await on Future objects until they either have a result or an exception set, or until they are cancelled.

  Les Futures sont habituellement utilisés pour permettre à du code bas niveau basé sur des fonctions de rappel (par exemple : les protocoles utilisant asyncio transports) d'interagir avec du code haut niveau utilisant async et await.

  Une bonne règle empirique est de ne jamais exposer des objets Future dans des API destinées à l'utilisateur. La façon privilégiée de créer des objets Future est d'appeler la méthode `loop.create_future()`. Cela permet aux implémentations alternatives de la boucle d'évènements d'utiliser leur propre implémentation de l'objet Future.

  Modifié dans la version 3.7: Ajout du support du module `contextvars`.

  `result`()

    Renvoie le résultat du Future.

    Si le Future est « terminé » et a un résultat défini par la méthode `set_result()`, ce résultat est renvoyé.

    Si le Future est « terminé » et a une exception définie par la méthode `set_exception()`, cette méthode lève l'exception.

    Si le Future a été annulé, cette méthode lève une exception `CancelledError`.

    If the Future's result isn't yet available, this method raises a `InvalidStateError` exception.

  `set_result`(result)

    Marque le Future comme « terminé » et définit son résultat.

    Lève une erreur `InvalidStateError` si le Future est déjà « terminé ».

  `set_exception`(exception)

    Marque le Future comme « terminé » et définit une exception.

    Lève une erreur `InvalidStateError` si le Future est déjà « terminé ».

  `done`()

    Renvoie `True` si le Future est « terminé ».

    Un Future est « terminé » s'il a été « annulé » ou si un résultat ou une exception a été définie par les méthodes `set_result()` ou `set_exception()`.

  `cancelled`()

    Renvoie `True` si le Future a été « annulé ».

    Cette méthode est habituellement utilisée pour vérifier qu'un Future n'est pas « annulé » avant de définir un résultat ou une exception pour celui-ci :

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

  `add_done_callback`(callback, *, context=None)

    Ajoute une fonction de rappel à exécuter lorsque le Future est « terminé ».

    L'argument callback est appelé avec l'objet Future comme seul argument.

    Si le Future est déjà « terminé » lorsque la méthode est appelée, l'exécution de la fonction de rappel est planifiée avec `loop.call_soon()`.

    L'argument nommé optionnel context permet de spécifier une classe `contextvars.Context` personnalisée dans laquelle la fonction de rappel s’exécutera. Le contexte actuel est utilisé si context n'est pas fourni.

    `functools.partial()` peut être utilisée pour passer des paramètres à la fonction de rappel :

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

    Modifié dans la version 3.7: Ajout de l'argument nommé context. Voir PEP 567 pour plus de détails.

  `remove_done_callback`(callback)

    Retire callback de la liste de fonctions de rappel.

    Renvoie le nombre de fonctions de rappel retiré. La méthode renvoie généralement 1, à moins que la fonction ait été ajoutée plus d'une fois.

  `cancel`()

    Annule le Future et planifie l'exécution des fonctions de rappel.

    Si le Future est déjà « terminé » ou « annulé », renvoie `False`. Autrement, change l'état du Future à « annulé », planifie l'exécution des fonctions de rappel et renvoie `True`.

  `exception`()

    Renvoie l'exception définie pour ce Future.

    L'exception, ou `None` si aucune exception n'a été définie, est renvoyé seulement si le Future est « terminé ».

    Si le Future a été annulé, cette méthode lève une exception `CancelledError`.

    Si le Future n'est pas encore « terminé », cette méthode lève une exception `InvalidStateError`.

  `get_loop`()

    Renvoie la boucle d'évènements à laquelle le Future est attaché.

    Nouveau dans la version 3.7.

Cet exemple crée un objet Future, puis crée et planifie l’exécution d'une tâche asynchrone qui définira le résultat du Future et attend jusqu'à ce que le Future ait un résultat :

    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())

Important

L'objet Future est conçu pour imiter la classe `concurrent.futures.Future`. Les principales différences sont :

- contrairement au Future asyncio, les instances de `concurrent.futures.Future` ne peuvent pas être attendues ;

- `asyncio.Future.result()` et `asyncio.Future.exception()` n'acceptent pas d'argument timeout ;

- `asyncio.Future.result()` et `asyncio.Future.exception()` lèvent une exception `InvalidStateError` lorsque le Future n'est pas « terminé » ;

- les fonctions de rappel enregistrées à l'aide de `asyncio.Future.add_done_callback()` ne sont pas exécutées immédiatement mais planifiées avec `loop.call_soon()` ;

- les Future asyncio ne sont pas compatibles avec les fonctions `concurrent.futures.wait()` et `concurrent.futures.as_completed()` ;