Site original : Sam & Max: Python, Django, Git et du cul
La 3.4 était la première version 3 à valoir le coup, et a donc été le déclencheur de la migration 2->3 qui trainant depuis si longtemps.
La 3.5(.3) a rendu asyncio
utilisable, incluant async
/ await
et corrigeant le bug abusé de get_event_loop().
La 3.6 est mon chouchou. Sa meilleure intégration de Pathlib et les f-strings en font un plaisir total à utiliser. En plus black ne tourne que dessus. Je suis autant que possible en 3.6, je l’ai même installé sur une vieille centos 7 chez un client.
Alors que vaut cette 3.7, et est-ce qu’il faut migrer ?
Et bien avec des améliorations de perfs partout et une syntaxe simplifiée pour les classes, c’est une belle release. La 3.6 est va être bien plus facile à avoir sous linux pendant un bon bout de temps et suffit amplement, donc je ne vais pas forcer le pas. Mais bon je l’ai quand même compilé par acquit de conscience.
Regardons ce qu’il y a au menu.
Clairement la feature phare de la release, les data classes sont une manière plus concise d’écrire des classes, s’inspirant de la bibliothèque attrs dont elles n’implémentent qu’un sous-ensemble.
Une très bonne nouvelle, car je n’installais jamais attrs: dépendre d’une lib juste pour ça m’embêtait et pour la sérialisation/validation j’utilise marshmallow.
Par exemple:
from dataclasses import dataclass @dataclass class Achat: produit: str prix: float quantite: int = 0 |
Ce qui va générer une classe toute ce qui a de plus normale, mais dont le __init__
, __repr__
et __eq__
automatiquement. Vous pouvez bien entendu ajouter les méthodes que vous voulez, comme d’habitude.
Il ne reste plus qu’à faire:
>>> print(Achat("foo", 2)) Achat(produit='foo', prix=2, quantite=0) |
Toute la magie est sélectivement désactivable, et une méthode __post_init__
est ajoutée à la classe qui fait exactement ce que vous pensez que ça fait.
En prime, on a aussi dataclasses.field
qui permet de fournir une factory pour un paramètre (typiquement list
, tuple
, dict
…).
Puis, comme un bonheur ne vient jamais seul:
>>> from dataclasses import asdict, astuple >>> print(asdict(Achat("foo", 2))) {'produit': 'foo', 'prix': 2, 'quantite': 0} >>> print(astuple(Achat("foo", 2))) ('foo', 2, 0) |
C’est récursif sur les dicts, lists, tuples et dataclasses \o/
Enfin, pour finir:
>>> from dataclasses import asdict, astuple >>> a = Achat("foo", 2) >>> b = replace(a, quantite=3, prix=1) >>> print(a, id(a)) Achat(produit='foo', prix=2, quantite=0) 140275795603296 >>> print(b, id(b)) Achat(produit='foo', prix=1, quantite=3) 140275775561456 |
Ouai ça déchire.
Much love to asyncio dans cette version.
Déjà, un truc qui aurait dû être là dès le début, la nouvelle fonction asyncio.run(), qui masque le setup de l’event loop pour vous.
On passe de :
loop = asyncio.get_event_loop() loop.run_until_complete(coro) |
à:
asyncio.run(coro) |
Juste ça, ça fait vachement moins peur aux gens. Et en prime ça évite qu’ils commencent à chercher la merde avec un setup custom de loop.
asyncio.current_task()
retourne la tache dans laquelle on est. D’ailleurs, un détail, mais on a maintenant l’équivalent de thread local, mais pour la coroutine en cours.
asyncio.get_running_loop()
retourne la boucle courante, mais seulement si elle existe. Elle lève une exception plutôt que de créer une loop comme get_event_loop()
si aucune loop n’est présente.
StreamWriter.wait_closed()
permet d’attendre qu’un stream se ferme. Les gars de aiohttp
doivent être contents.
Task.get_loop()
retourne la boucle de la tache. Pour le multi-threading avec plusieurs loops, c’est cool.
loop.create_server()
a maintenant un argument start_serving
qui controle si on veut le lancer immédiatement. J’ai toujours du mal à croire que des dev qui sont capables de participer à la stdlib ont pu commiter un code qui instancie et enchaine sur un effet de bord. Heureusement c’est corrigé.
Les handlers retournés par loop.call_later()
retournent leur ETA avec .when()
et ont une méthode .cancelled()
.
TCP_NODELAY
est utilisé par défaut sous Linux. Des perfs gratuites, merci. Sans surprise contribué par Victor Stinner
^^
Les intensions acceptent maintenant async/await
.
Et enfin, les exceptions des taches annulées ne sont plus loggées. Parce que forcément quand on crashait tout, le log devenait un peu chargé…
Bon, asyncio était déjà très utilisable en 3.6, ne n’exagérons pas. L’important étant d’utiliser le mode debug, gather()
et run_until_complete()
, ce qui devrait être écrit en gros, en rouge dans la doc.
Mais toutes ces modifications sont bienvenues.
Ah, oui, les perfs ont été aussi améliorées… Mais c’est le cas partout.
Le focus sur les perfs de Python augmente doucement. La 3.6 avait amorcé la tendance, et ça se confirme. J’attends d’avoir des retours sur des mises en prod un peu serieuses pour savoir si ça a payé.
Le temps de démarrage de Python est d’ailleurs pas mal pointé du doigt. Certes, on est pas au niveau de l’outre sclérosée que constitue nodejs au réveil, mais c’est pas une référence. Donc, des choses sont mises en place. Notamment python -X importtime
qui va afficher le temps que prend chaque import.
Des aménagements ont aussi été fait pour accélérer le module typing
, maintenant que l’usage des type hints pour les annotations est entériné. Un side effect sympas est que les classes que vous allez écrire seront plus rapide à instancier, et les méthodes plus rapide à résoudre.
D’ailleurs, les type hints sont maintenant résolus paresseusement, à la fois pour améliorer la vitesse de chargement et pour faciliter l’auto-référencement.
breakpoint() est techniquement un alias configurable à import pdb; pdb.set_trace()
. Ça à l’air de rien, mais c’est super:
debugger
en JS parce que c’est simple de comprendre ce que ça fait au premier coup d’oeil.Ça vient bien entendu avec une variable d’environnement et d’un hook dans sys
pour custo le comportement.
La spec garanti que les clés vont garder leur ordre d’insertion. C’était déjà le cas en 3.6, la 3.7 rend juste la mesure officielle.
Ne jetez pas OrderedDict à la poubelle pour autant, car il préserve l’ordre des clés après suppression également.
Et ne peuvent donc plus être écrasés par erreur.
On va pouvoir définir un __getattr__
sur les modules (surtout utile pour le lazy loading) et un __class_getitem__
pour pouvoir faire MaClass[]
sans utiliser de metaclass.
Le processus pour avoir des docs dans d’autres langues est maintenant officiel. Pour l’instant le jap, le koréen et le kokorico
La connerie de les cacher a été corrigée. Qui a pensé que c’était une bonne idée ? Mais seulement pour le script principal, ce qui va permettre aux des des libs de les voir sans faire chier les utilisateurs.
python -X dev
va devenir votre nouvel ami, activant tout un tas de fonctions de debug coûteuses en production. Notamment plus de warning, asyncio debug mode, le faulhandler qui dump la stacktrace en cas de catastrophe, etc.
Un même fichier donnera maintenant toujours un même .pyc. C’est pour les packagers et les amateurs de sécu.
L’exception va maintenant afficher le nom du module et son __file__
path si from ... import
broute. Ça va rendre les imports circulaires, la plaie des gros projets Python, plus facile à debugger.
https://docs.python.org/3.7/whatsnew/3.7.html#importlib-resources
Introduction de importlib.resources, un remplacement pour le détestable pkg_resource
qui va rendre sans regret de ma part mon article obsolète.
Autre ajout notable: README.rst
est maintenant reconnu et ajouté automatiquement quand on fait son paquet cadeau. Puisque maintenant pypi accept le markdown, ça aurait été cool de le faire avec les .md
également.
Sensible à la nanoseconde. Perso je m’en bats les steaks mais je me suis dit que je ferai passer l’info.
Rien à ajouter, si ce n’est qu’entre SimpleNamespace et les dataclasses, je crois qu’on a de quoi voir venir. Même si j’aimerais avoir un literal pour les namestuples sous la forme de (foo=1, bar=2)
mais ça a été refusé.
Quelques outils en plus, dont un context manager qui ne fait rien (rigolez pas, c’est super utile !), et des contexts managers async.
Ok, plutôt bottox. C’est cosmétique, mais c’est bienvenu: des aménagements pour rendre les appels un poil plus courts, notamment dans le cas de la capture des stdx.
…
…
…
Et encore plein d’autres mini trucs.
C’est dispo en DL pour windows et mac. Pour linux, comme d’hab, soit on attend la mise à jour des depôts/ppa/etc, soit on compile à la main (étonnamment facile, si on se rappelle de faire make altinstall
et pas make install
), soit on utilise l’excellent on install pyenv et pyenv install 3.7
.