Site original : Sam & Max: Python, Django, Git et du cul
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:
Sur ces questions, du travail est activement en cours.
Pour le multi CPU, un modèle propre permettra d’utiliser plusieurs interpréteurs en parallèle en partageant des valeurs
sans avoir à les sérialiser.
Pour les perfs, ce sera un taf plus long, mais:
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 partout. nuikta, le compilateur Python, supporte maintenant await/async.
On est sur la bonne route.
L’année 2016 va être trop cool, et dans mon enthousiasme, j’aimerais écrire à propos de choses que j’aimerais vraiment voir arriver dans Python.
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 exist 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.
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 les 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] |
Si vous voulez tous les carrés des nombres au-dessus de 5, vous pouvez faire:
(x * x for x in numbres 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 numbres) |
Alors certes, je ne suis pas pour transformer Python en Haskel 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.
Je suis hésitant sur cette feature car c’est très tentant de faire de 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.
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.
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
.
Après, le prenez pas mal hein. J’adore async
/await
. Vive asyncio
! Mais la syntaxe pourrait être plus naturelle, plus proche du comportement des générateurs, d’autant que ça se base dessus.