Evolution de Python


La communauté Python est assez d’accord ces derniers temps. Maintenant que le plus gros de la débâcle Python2/3 est derrière nous (en attendant le contre coup des retardataires de 2020) et qu’on a un modèle d’IO async bien clean, les trucs qui fâchent sont assez clairement délimités:

  • Le packaging.
  • Le multi-core.
  • Les perfs.

Sur ces questions, du travail est activement en cours.

Pour le multi-core, Eric Snow propose un modèle propre qui permettra d’utiliser plusieurs interpréteurs en parallèle en partageant des valeurs sans avoir à les sérialiser.

Concernant l’amélioration des perfs, ce sera un taf plus long, mais:

  • Les opérations sur les bytes ont des perfs bien améliorées pour la 3.6.
  • Victor Stinner et Yury Selivanov travaillent sur des trucs très cools. Jetez un coup d’œil aux mailling lists sur les sujets “FAT Python”, “PEP 509/510/511” et “Explicit variable capture list” pour voir tout un tas d’optimisations prévues, ou permettant d’en prévoir.
  • Pyjion, la JIT de Microsoft, un des projets les plus prometteurs pour accélérer Python, commence à faire parler d’elle.
  • Dropbox, chez qui travaille Guido Van Rossum, bosse sur son implémentation de Python également.
  • Et bien entendu Pypy continue son bonhomme de chemin.

Bref, y a du potentiel.

Pour le packaging, les wheels vont enfin arriver sous Linux, ce qui fait qu’on pourra bientôt pip installer des binaires sur les 3 OS majeurs. Peut-être même BSD qui sait.

Nuikta, le compilateur Python, supporte maintenant await/async. J’ai beaucoup d’attentes envers ce projet, ça mérite un don du mois :)

On est sur la bonne route.

L’année 2016 va être trop cool, et dans mon enthousiasme, je vais écrire à propos de choses que j’aimerais vraiment voir arriver dans Python.

try/except error inline

Beaucoup de codes en Python ressemblent à ça :

try:
    val = faire un truc
except MonErrorALaNoix:
    val = "valeur par default"

Par exemple :

try:
    val = stuff[index]
except (IndexError, TypeError):
    val = None

Ce sont des opérations si courantes qu’on a plein de raccourcis comme dict.get ou next(i, None). En effet, en Python try/except n’est pas juste un mécanisme de gestion d’erreur, c’est un mécanisme de contrôle de flux à part entière.

Car franchement, ça fait chier de se taper 4 lignes pour écrire ça. En effet, on a bien les expressions ternaires pour les if/else:

val = truc if bidule else machine

Et bien il existe un PEP (rejeté) qui propose ça:

val = faire un truc except MonErrorALaNoix: "valeur par default"

J’adore. C’est pratique, générique, propre.

Bien entendu ça peut être abusé, comme les expressions ternaires, pour faire de la merde illisible. Mais j’ai rarement vu le cas pour les précédentes, donc ça devrait aller.

slices sur les générateurs

Les générateurs, c’est formidable. C’est iterable. On peut les utiliser partout où on utilise les listes.

Sauf si on doit les limiter en taille.

Alors là, c’est relou.

Par exemple, récupérer les carrés des nombres pairs entre 0 et 100, puis limiter le tout a 10 éléments après le 5e:

from itertools import islice
g = (x * x for x in range(100) if x % 2 == 0)
g = islice(g, 5, 15)

Ca serait tellement plus simple de pouvoir faire:

g = (x * x for x in range(100) if x % 2 == 0)[5:10]

callable dans les slices

Si vous voulez tous les carrés des nombres au-dessus de 5, vous pouvez faire:

(x * x for x in numbers if x > 5)

Mais si vous voulez tous les nombres à partir du moment où vous rencontrez un nombre au-dessus de 5 ?

from itertools import dropwhile
numbers = dropwhile(lambda x: x > 5, numbers)
(x * x for x in numbers)

Alors certes, je ne suis pas pour transformer Python en Haskell et balancer des formules magiques comme:

(x * x for x in numbers[a -> a > 5])

Mais juste m’éviter l’import et pouvoir faire ça:

def start(x):
    return x > 5
(x * x for x in numbers[start:])

Ca serait cool.

with var dans les expressions génératrices

Je suis hésitant sur cette feature car c’est très tentant de faire des one liners trop longs avec, mais:

(x.split()[1] for x in truc if x.split()[1] == 1)

C’est con de faire 2 fois split quand même.

(y for x in truc 
   with x.split()[1] as y 
   if y == 1)

Bon, ça peut rapidement devenir illisible, donc à méditer.

async optionnel

Je cherche toujours à comprendre pourquoi async est nécessaire.

Avec les générateurs, la présence de yield fait détecter automatiquement la fonction comme fonction génératrice:

def stuff(): # pas de machin def
    yield bidule # python comprends que c'est un générateur

Avec await, ça devrait être pareil:

def stuff():
    await bidule # bim, c’est une coroutine !

Pas besoin de async. Si on veut faire une coroutine sans un seul await, il y a toujours @asyncio.coroutine.

async reste très utile pour async for et async with, mais perso j’aurais préféré avoir un await with et un await for et pas de async.

On peut imaginer l’inverse aussi : tabler sur “explicit is bettern than implicit” et rajouter un gen def pour les générateurs et obtenir la parité.

Après, le prenez pas mal hein. J’adore async/await. Vive asyncio ! Mais la syntaxe pourrait être plus cohérente, plus proche du comportement des générateurs, puisqu’un coroutine n’est qu’un générateur spécialisé.

23 thoughts on “Evolution de Python

  • Jean Michel PHP

    Niveau perf, on peut espérer quelque chose qui se rapproche de PHP7? :°

    (Oui je sais, tout le monde s’en fout, mais il m’en faut peu pour avoir des complexes.)

  • Atrament

    (x.split()[1] for x in truc if x.split()[1] == 1)

    ça peut pas se faire déjà avec

    ( y[1] for y in map(str.split, truc) if y[1] == 1 ) ?

    Pasque autant le reste y’a plein de trucs que je trouverais cool, autant j’ai jamais été très gêné par ça…

  • Gordon

    Victor Stinner a justement donné une conférence hier au FOSDEM pour parler de FATPython (ça a été filmé, la vidéo devrait être rapidement dispo)

  • bigduke

    Wow cool tout ça !

    Je me sens concerné par la remarque sur les retardataires en 2020 :D mais j’suis pas un pro de l’info, “I’m just script kidding” !

    Jusqu’ici je restais sur la 2.7 pour certaines librairies mais il faut que je saute le pas.

    Et ça me fera plaisir de plus utiliser “from future import division”…

  • mdupuy

    Vu que ce post parle d’interpréteurs et de vitesse d’exécution, je pose ma pèche ici et parle différents interpréteurs et leur statut, ça peut intéresser des gens.

    Déjà, niveau interpréteurs alternatifs, on a les historiques Jython et IronPython ; ces deux projets sont des interpréteurs python tournant dans la JVM existante d’un autre langage, respectivement la JVM Java et le CLR/.Net de C#, apportant ainsi différents bénéfices, entre autre un vrai ramasse-miette (garbage collection) et pas du comptage de référence (reference counting) comme CPython qui fait bien le job mais atteint rapidement ses limites, et aussi des VRAI threads qui carburent, sans problème de GIL comme CPython. Ils ont aussi en commun d’avoir été peu adoptés (très peu dans le cas d’IronPython) et qu’ils sont plus très vivant (très peu dans le cas d’IP) : dernière release de JP: 05/15 ; IP: 06/14. Ça fait mal. De plus, si à leur sortie ils donnaient par moment de meilleures perf que CPython, ce dernier s’est beaucoup amélioré et maintenant ils se valent. De plus, tous les deux sont très lourds, avec une empreinte mémoire beaucoup plus grosse et un startup time sans comparaison avec CPython. À déployer, c’est complètement la mort aussi, rien à voir avec apt-get install python/pypy. Très beaucoup la mort pour obtenir un IronPython qui tourne sous Mono sous Ubuntu. Ces projets sont bien partis pour disparaître s’ils ne changent. Et le support de python3 est inexistant pour tous les deux.

    Ensuite vient Pypy, l’interpréteur Python en python orienté vitesse. Pypy vise à être un dropin remplacement, c’est à dire qu’ils suffit de l’installer et de changer les commandes “python truc” par “pypy truc” et hop ça marche. Ça fonctionne, à condition de ne pas utiliser de modules compilés en C. Si c’est néanmoins le cas, Pypy peut utiliser les modules en C de CPython moyennant recompilation, mais attention, les perfs sont moins bonne qu’avec CPython, du au fait que l’API vient de CPython et impose à Pypy, un interfaçage/fonctionnement qui n’est pas le sien. Le support de Python 3 est minimum, Python 3.2 est supporté depuis 1 an ou 2, autant vous dire qu’on est pas en avance.

    Vous avez pu tomber sur des noms genre Unladden Swallow et Stackless Python : ce sont des Pypy-like antérieurs qui sont morts et qui ont été mergé dans Pypy (du moins ce qui était récupérable).

    Ensuite est venu il y a un an le “Pypy” de Dropbox, Pyston. Tout le monde a tapé sur Dropbox pour avoir réinventé sa roue carrée avec Pyston, Dropbox a répondu qu’ils utilisent une approche différente de Pypy, ils utilisent un JIT method-at-a-time au lieu d’un tracing JIT, méthode qui a donné de si bons résultats avec le moteur de javascript V8 . Et surtout, ils s’appuient sur LLVM, la “machine virtuelle pour le bas-niveau”. LLVM étant par ailleurs soutenu par des grands noms genre Apple et Intel, si Dropbox ne merde pas, ça pourrait donner un truc intéressant.

    Le truc qui fait tousser avec Pyston, c’est que les créateurs ne déclarent ne vouloir que viser Python 2.7 et ne pas envisager de supporter python3. On a du mal à croire que Guido van Rossum travaille pour cette boite.

    Le blog de Pyston, intéressant : http://blog.pyston.org/.

    Un énorme écueil d’écrire un interpréteur alternatif à CPython étaient les modules en C de la bibliothèque standard, une bonne partie étaient écrit en C, donc si vous faisiez un interpréteur alternatif, fallait aussi vous recoder dans un langage adapté tous les modules de la lib standard que vous ne pouviez utilisez, ce qui implique de faire 10.000 tests pour s’assurer qu’ils ont exactement le même comportement, ce qui est extrêmement dur. Depuis 2 ans (je crois), CPython fourni un recode en Python de ses module en C qui passent exactement la même suite de test et qui sont donc “garantis” (modulo erreur humaine, c’est dur comme tâche) de se comporter exactement comme leurs congénère en C. C’est une énorme charge de travail en moins pour les développeurs d’interpréteurs alternatifs.

    De tous, seul Pypy est le seul qui s’approche vaguement d’un “concurrent” sérieux à CPython. Et encore, c’est pas encore le dropin remplacement parfait. Et tous ont un support de Python3 qui est inexistant, sauf Pypy qui est insuffisant :). Et tous, en tant que VM complète (donc lourde) ou visant à optimiser le code (et donc analyser), ont des temps de démarrage et d’atteinte de l’efficacité sans commune mesure avec CPython. Ils ne sont intéressants qu’en cas de long-running (genre, vos sites django).

    Parmi les news relatives à la vitesse de Python que l’article de S&M ne mentionne pas, la nouvelle release de la JVM vient avec un meilleur découplage des éléments la composant, et du coup il devient facile de l’utiliser pour un autre langage. IBM a fait un proof-of-concept en faisant un interpréteur python, qu’ils vont open-sourcer (et faire pareil avec Ruby). Pas d’altruisme là-dedans, c’est pour montrer au monde que leur VM est bien fichue. Ça pourrait être le nouveau Jython : http://www.infoworld.com/article/3014128/open-source-tools/ibms-open-source-jvm-project-could-also-speed-ruby-python.html.

    Aussi, Microsoft s’étant visiblement un peu amouraché de Python, on peut s’attendre que leur coopération à Python ne s’arrête pas là (ou si).

    Après, la vérité triste est que les langages dynamiques sont très durs à optimiser, parce qu’ils sont justement dynamiques, surtout Python où tout est modifiable, et donc l’intepréteur/VM ne peut être sûr de rien et ne peut pas supprimer pleins de tests/résolution/recherche, et que Python, malgré toutes ses implémentations pleine de bonne volonté, ne sera jamais aussi rapide que le C, ni même que Java. La dernière fois que j’ai regardé (~3 ans), le benchmark game donnait python 20x plus lent que le C, contre 2x pour le Java. Ça fait réfléchir. Tous les efforts poussés à fond, on tapera peut être le 5x plus lent que le C :)

    Voila, vous savez tout sur l’histoire des différents intepréteurs Python. Avec ça, vous pourrez vous la pétez en soirée et niquer des tonnes de meufs.

    Ou pas.

  • dineptus

    L’encodage du code s’est tout cassé, hier on avait bien les < > mais aujourd’hui ca donne des >

  • Sam Post author

    @Jean Michel PHP : impossible à savoir avant que le boulot soit fini. Et même la, faut faire des benchmarks adaptés, ce qui est pas gagné, le monde de la comparaison de perfs étant pas vraiment impartial.

    @Atrament : effectivement, très bon usage de map. Je vais faire comme cela à présent.

    @mdupuy : je te mail, ce genre de comment ça mérite une promotion :)

    @dineptus : corrigé.

  • buffalo974

    Que peut on espérer en terme de perf en compilant un jeu 2D sous pySFML versus

    C++ / SFML ?

    Pourra-t-on dans le futur scripter en python avec l’ Unreal Engine ?

    Un mini-article un jour sur Nuitka ?

  • Victor Stinner

    typo: “Yury Selivan” => Yury Selivanov. Magic Stack (magic.io) lui donne du temps pour expérimenter ses optimisations et ça, c’est cool ;-)

  • Sam Post author

    Merci, j’ai tout pêté au copier/coller. Déjà qu’on écorche son nom sur la mailling list :) Ta prez au FOSDEM a fait grande impression, mais maintenant les gens vont avoir de grosses attentes sur le résultat ^^

  • albert

    Pendant ce temps, nodejs et Go croissent…à vitesse grand V. Attendez encore 3-4 ans et des django like chez Nodejs et Go vont dominer et ça va faire mal.

  • Sam Post author

    Pour le moment je vois plutôt l’inverse. Je crois des tas d’équipes et devs qui reviennent du hype de nodejs et Go et retournent sous C#, Java, Php et Python. Ca fait chier de voir Python dans cette liste, mais bon, les gens en ont marre des trucs pas stables, du manque de tooling, de la doc pourrie et des projets jetables.

  • Victor Stinner

    “Ta prez au FOSDEM a fait grande impression, mais maintenant les gens vont avoir de grosses attentes sur le résultat ^^” Habituellement, j’ai de bon retours sur mes conf mais aucun contribution juste après. Là l’auteur initial du patch “function inlining”, Dave Malcolmm, qui avait écrit le patch en 2010 ( https://bugs.python.org/issue10399 ), m’a envoyé un pull request pendant le week-end pour l’implémenter !? Je l’ai croisé à la sortie de la conf, c’est un collègue qui bosse désormais sur GCC (notamment le JIT compiler de GCC, libgccjit). La pull request : https://github.com/haypo/fatoptimizer/pull/1

  • albert

    @sam

    Je partage ta remarque “des trucs pas stables, du manque de tooling, de la doc pourrie et des projets jetables” pour NodeJS, mais pas pour Go, c’est stable, il y a de vrais outils de dev et niveau déploiement c’est un pur bonheur.

    Si je raisonne en dev web, je préfère toujours Python, si je raisonne en tant qu’architecte et admin je préfère Go, tu passes de 20 serveurs à 2 ;) et ça ton chef adore. Quand tu as goûté aux channels et goroutines, tu ne peux plus revenir en arrière. Sur du parsing de milliers de flux rss, j’ai divisé le temps de traitement par facilement 10.

    Les patterns suivantes :

    https://divan.github.io/posts/go_concurrency_visualize/?utm_source=golangweekly&utm_medium=email

    Et bien tu auras du mal à faire la même chose en Python.

  • Sam Post author

    Avec asyncio et un processpool executor, tu vas obtenir de très bonnes perfs facilement sur Python. Bien entendu, ça sera plus lent que sur un langage compilé, mais c’est généralement assez rapide, et je traite des crawlers qui parsent, dl et encode des milliers de vidéos par jour.

    Apparement la cause majeur de quitter go est son système de typing et d’erreur qui sont super relous, et le fait que c’est dur à étendre. Egalement les docs et libs en Go qui sont encore incomplètes, immatures, incompatibles, etc. Même si la plateform Go est stable, son écosystème est encore en construction.

  • Sam Post author

    @Victor Stinner : excellent ! C’est ce qui manque sur Python : plus d’experts qui se collent sur ces petits trucs pointus. Car des généralistes comme moi on en a à la pelle, mais des mecs capables d’implémenter des bout de JIT, ça manque franchement (sont sans doute tous en train de bosser chez Google ou Oracle).

  • albert

    1 pour Victor, ce gars là est un des gars les plus compétents en Python au monde ! C’est un gars qui kiffe l’optimisation et c’est français ! Oui Monsieur ;)

    Même si j’apprécie Go, mon langage préféré demeure Python. Mais je me rends compte qu’en faisant du Go, j’améliore mes techniques en Python également et ça fait jamais de mal de revoir un peu du bas niveau (j’aimais bien le C) pour être encore meilleur avec des langages avec des niveaux d’abstraction plus hauts.

    Loin de moi l’idée de comparer Python et Golang, ce sont 2 langages conçus différemment. Maintenant, le top est d’avoir une architecture qui mixe les 2.

    Longue vie à Python !

    Par contre NodeJS, j’ai testé, c’est performant mais le JS ça me dégoûte trop, c’est le bordel, c’est pas maintenable, c’est tellement pourri qu’on a inventé les craftsmen ;)

    Sam, tu m’as redonné espoir en citant les différents projets dont je n’avais pas connaissance !

    Vive Python, vive la France et vive le claque-boule !

  • batisteo

    Bon bah moi je vais écrire Rusthon, un interpréteur Python en Rust.

    Nan j’déconne, je comprends rien à Rust.

    Quoi que maintenant que j’y pense, ça pourrait être sympa, un meta hello world, pour apprendre Rust…

  • Sam Post author

    Améliorer les bindings Rust = Python par contre, c’est super important.

  • resethread

    L’image a l’air de sortir tout droit d’un hentai.

    A part ça c’est un super blog qui me donne envie de changer un peu de PHP et JS.

Comments are closed.

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