async / await, la feature de dernière minute de Python 3.5


Ces mots clés vont-ils être introduits pour Python 3.5 alors qu’elle est déjà en alpha 4, et que la feature freeze est pour la prochaine version ? La release finale est prévue pour le 22 mai, ce qui est à peine un mois, pour une nouveauté formalisée début avril et toujours en draft.

J’avoue qu’à première vue, l’idée ne m’a pas enthousiasmé.

D’abord, parce que ça n’apporte pas grand chose de nouveau. Les coroutines, ça existe depuis un bail maintenant, et asyncio les exploite avec yield from.

Pour résumer, la proposition est d’introduire deux mots clés tels que :

import asyncio
 
@asyncio.coroutine
def truc():
    bidule()
    yield from machine_asynchrone()
    chose()

Puisse être écrit :

async def truc():
    bidule()
    await machine_asynchrone()
    chose()

(Notez que la coloration syntaxique ne les prends pas en compte :))

Le PEP propose également l’introduction de deux syntaxes pour avoir des context managers et des boucles asynchrones: async with et async for

Et ça ne m’a pas chauffé parce que :

  • Je ne voyais pas l’intérêt d’ajouter des mots clés pour faire un truc qu’on peut déjà faire. Le faible nombre de key words dans Python est pour moi une feature.
  • Il n’y a rien que ça permette qu’on ne pouvait pas faire avant.
  • Ça me parait un peu fait à la dernière minute, introduit comme un voleur avant la release.
  • C’est franchement moche le async avec un autre mot clé et ça pête toutes les attentes qu’on a eu sur la syntaxe du langage jusqu’ici : maintenant on a des qualificateurs, ce qu’on avait jamais eu avant. Ca ajouté aux type hintings, qui sont déjà très laids, c’est charger la mule.

Entre temps j’y ai réfléchi et avec le recul, je commence à voir de sérieuses qualités à cette proposition :

  • On distingue clairement le code qui est pour créer des générateurs, et le code asynchrone. Ce sont des choses qui n’ont sémantiquement rien à voir, et utiliser yield from pour les deux rendait tout ça bien confus.
  • C’est moins à taper : pas besoin d’importer un décorateur de 3 km et l’apposer, et quand on a pas mal de point d’arrêt, await c’est moins chiant à tapper que yield from et plus joli.
  • Ca évite pas mal de bug subtiles qui se glissent quand on utilise une coroutine pour la première fois sans comprendre tout le système. Par exemple si on vire tous les yield from d’une coroutine, c’est la merde, ce qui n’est pas le cas pour les await.
  • Quand on fait une boucle sur un generateur on sait tout de suite si on va avoir un point d’arrêt ou non.
  • Les mêmes mots clés sont utilisés dans d’autre langage, ce qui permet aux migrants de comprendre le principe bien plus vite qu’avec yield qu’il faut assimiler, et apprendre à distinguer dans ses deux formes.

Bref, async et await sont plus explicites, amènent moins de confusion, évitent des bugs et d’une manière générale permettent une compréhension plus rapide du code, mais également du concept de l’asynchrone en général, particulièrement pour les débutants.

Car j’avais en effet vu pas mal de gens ne rien piger aux coroutines.

Du coup, même si j’aimerais que le truc ne soit pas baclé et inséré à la va vite avant la bêta, je trouve finalement que c’est pas mal. La syntaxe n’est pas fantastique, mais je n’arrive pas à imaginer mieux (alors que clairement, les types hinting seraient 100x mieux dans la docstring avec le format existant pour sphynx), donc inutile de critiquer si on apporte pas de solution.

9 thoughts on “async / await, la feature de dernière minute de Python 3.5

  • LeMeteore

    Entierement d’accord. Du haut de ma tres petite experience avec les coroutines, il m’arrivait souvent de survoler mon code, a la recherche d’une ligne vite fait, et de ne voir que des “yield from” partout. Cela pouvait etre assez troublant des fois. Je pense en effet, que cette syntaxe, c’est surtout pr une lisibilité meilleure/fluide.

  • mothsART

    Effectivement, y’a de bonnes idées derrière tout ça!

    Bon, avant qu’on l’utilise pleinement, va falloir attendre un moment : les libs/framework qui supportent plusieurs versions de python implémenteront raisonnablement cette nouvelle syntaxe uniquement quand la version la plus ancienne sera la 3.5!

    Pour Django, par exemple, on peu l’estimer pour 2025 ?!

    Sinon, moyennement d’accord sur l’utilité pour les débutants : L’asynchrone n’est pas dédié au débutant à mon sens.

    J’aurais tendance à dire qu’un débutant ne devrait pas s’en préoccuper avant d’avoir pris de la bouteille.

    Sinon, il court de gros risques : débogage délicat, conception foireuse, code non maintenable et j’en passe.

    J’estime que le cycle naturel de maturation d’un dev passe par l’intérêt de l’asynchrone (faire de l’async sans en avoir un intérêt immédiat ou a moyen terme risque de dégoutter plutôt que d’enthousiasmer) mais qu’il ne doit pas être prématuré.

    De souvenir de mes cours d’info, les profs avaient insisté sur les notions de pointeur, de référence ou de callback.

    J’avais beau gardé au fond de mon subconscient la logique, que c’était primordiale, ce n’est que quand je me suis retrouvé confronté à des situations ou ces notions devenaient “obligatoires” que le déclic c’est opéré.

    Mon raisonnement reste néanmoins limité à mon expérience personnel.

  • Ludovic Gasc (GMLudo)

    L’intérêt de cette nouvelle syntaxe c’est que le pattern async devienne un first class citizen en Python, comme dans d’autres langages comme Javascript, C# ou autre.

    L’utilisation de générateurs pour implémenter ceci est + un détournement qu’une fonctionnalité de base.

    Le problème avec les yield from et Cie, c’est qu’il y a 2 patterns à apprendre pour maîtriser AsyncIO.

    En ce qui concerne le fast track, ça fait un moment que cette idée germe dans la communauté AsyncIO, donc ce n’est pas totalement une surprise.

    De plus, au + vite c’est dans Python, au + vite la toolbox autour d’AsyncIO peut migrer vers cette nouvelle syntaxe.

    Pour l’instant, la communauté AsyncIO est petite et composé d’early adopters, c’est le bon moment pour changer avant que les vieux Pythonnistes de Python 2 débarquent dans Python 3, justement pour éviter un schisme comme il y a entre Python 2 et 3.

  • geekingfrog

    C’est amusant ça, venant du monde JS. yield est arrivé avec es6 et async/await est en discussion pour es7. Ça rend en effet le comportement de python et js très similaire lorsqu’on touche à l’asynchrone.

  • Zanguu

    Je confirme, venant de C# j’ai, dés le titre de l’article, compris à quoi servaient les 2 mot clés en question, alors que le yield est pour moi associé aux générateurs.

    Aussi, même si l’asynchrone est un concept avancé, avoir un mot clé qui permet de faire deux choses peut être un frein à la compréhension.

  • herison

    On pourra faire des

    x = await ?

    A par ça, je ne pige pas l’intérêt du async avant le def,

    Avant les coroutines, du moment qu’il y avait yield la fonction devenait une fabrique de générateur.

    Pourquoi ne pas dire que du moment qu’il y a un await, c’est une fabrique de coroutine et séparer définitivement les concepte de générateur et coroutines ?

Comments are closed.

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.