# Futures

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`.

  Ajouté 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.

  Gardez une référence au résultat de cette fonction pour éviter de voir une tâche disparaitre au milieu de son exécution.

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

  Obsolète depuis la version 3.10: Un `DeprecationWarning` est levé si obj n'est pas un objet se comportant comme un Future, si loop n'est pas spécifié et s'il n'y a pas de boucle d'évènements en cours d'exécution.

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

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

  Obsolète depuis la version 3.10: Un `DeprecationWarning` est levé si future n'est pas un objet se comportant comme un Future, si loop n'est pas spécifié et s'il n'y a pas de boucle d'évènements en cours d'exécution.

## 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 est un objet qui peut être attendu (awaitable). Les coroutines peuvent attendre les objets Future jusqu'à ce qu'ils renvoient un résultat, ils lèvent une exception ou qu'ils soient annulés. Un Future peut être attendu plusieurs fois et le résultat est le même.

  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`.

  Obsolète depuis la version 3.10: Un `DeprecationWarning` est levé si loop n'est pas spécifié et s'il n'y a pas de boucle d'évènements en cours d'exécution.

  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 an `InvalidStateError` exception.

  set_result(result)

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

    Raises an `InvalidStateError` error if the Future is already done.

  set_exception(exception)

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

    Raises an `InvalidStateError` error if the Future is already done.

  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(msg=None)

    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`.

    Modifié dans la version 3.9: Ajout du paramètre msg.

  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é.

    Ajouté 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()` ;

- `asyncio.Future.cancel()` accepts an optional `msg` argument, but `concurrent.futures.Future.cancel()` does not.