Sommaire
Opérateur d’assignation
Jusqu’à présent, Python refusait tout simplement d’assigner une variable dans un if
ou équivalent. Concrètement, if var = True:
lève une erreur de syntaxe. Cela évite l’erreur classique d’assigner une valeur en oubliant le deuxième égal de l’opérateur de comparaison ==
. Dans les langages autorisant l’assignation dans les expressions, l’utilisation de condition Yoda aidait à se défendre d’une erreur humaine. Dans Python, c’est, de toute façon, impossible.
Mais voilà, il y a certains cas où l’assignation et le test sont très liés. Et l’opérateur d’assignation est très pratique. Le cas le plus courant est l’exécution d’expression rationnelle :
m = re.match('motif', 'valeur')
if m is not None:
...
À partir de Python 3.8, un opérateur particulier permet d’assigner et de vérifier la valeur : l’opérateur :=
. Les Anglo‑Saxons l’appellent walrus, c’est‐à‐dire morse (comme l’animal), car il ressemble à un smiley représentant les yeux et les défenses du morse. Désormais, on peut écrire le code précédant comme suit :
if (m := re.match('motif', 'valeur')) is not None:
...
La concision de cet opérateur est appréciable. Et il est difficile de le confondre avec l’opérateur de comparaison.
Le grand débat
Cet opérateur a été l’occasion d’un débat passionné. Est‐ce que cet opérateur est une variation de ==
ou bien faut‐il réutiliser le mot‑clef as
comme dans except Exception as e
?
Guido van Rossum, créateur du langage, a utilisé son super‐pouvoir pour imposer le petit morse. Mais cela lui a coûté et il a démissionné de son poste de BDFL.
Arguments exclusivement positionnels
Python permet déjà de déclarer des arguments de fonction exclusivement nommés. Python 3.8 ajoute la possibilité de déclarer des arguments exclusivement positionnels. Voici un exemple :
def f(a, /, b):
print(a, b)
f(0, 1) # valide
f(a=0, b=1) # invalide car a est nommé
f(0, b=1) # valide
Certaines API en tireront parti pour simplifier la validation des arguments. À noter, le nom d’un argument positionnel peut être réutilisé en argument nommé. Par exemple :
def f(a, /, **kw):
print(a, kw)
f(0, a=1) # valide ! Affiche: '0 {"a": 1}'
Interpréteur async
Cette nouveauté n’est pas mise en avant, pourtant elle est bien pratique. En exécutant le module asyncio
, CPython propose désormais un interpréteur Python acceptant le mot clef await
pour exécuter une co‑routine :
Avant :
$ python3
Python 3.7.3 (default, Apr 3 2019, 05:39:12)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> await asyncio.sleep(1)
File "", line 1
SyntaxError: 'await' outside function
>>>
Désormais :
$ python -m asyncio
asyncio REPL 3.8.0
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> await asyncio.sleep(1, result='hello')
hello
On pouvait avoir à peu près lʼéquivalent en lançant une boucle par co‑routine :
$ python3
Python 3.7.3 (default, Apr 3 2019, 05:39:12)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> asyncio.run(asyncio.sleep(1, result='hello'))
'hello'
>>>
À suivre !
Pickle v5
Pickle est un protocole de transmission de données dans un format interne à Python. Le Français Antoine Pitrou a proposé une version 5 du protocole permettant de référencer des données transmises hors bande. Cela permet d’utiliser un canal de communication plus performant pour les gros volumes de données qu’on veut transmettre à Python.
Petit rappel, Pickle n’est pas un format pour communication publique. Il est très facile d’injecter du code dans votre programme via ce protocole. Utilisez‐le uniquement pour les communications internes à vos projets.
Et plus
Le mini‐langage de formatage de chaîne accepte un nouveau spécificateur f-string : {var=}
qui affiche le nom de la variable et sa valeur. Cela économise une duplication lorsqu’on écrit des messages de débogage.
CPython peut maintenant stocker les fichiers bytecode dans un dossier de cache spécifique, ailleurs que dans des dossiers __pycache__
un peu partout. Il faut pour cela définir le paramètre PYTHONPYCACHEPREFIX
via différentes méthodes. Cela permet, par exemple, de livrer du code source en lecture seule, sans précompiler, tout en laissant la possibilité d’avoir un cache de bytecode parallèle.
Le travail du Français Victor Stinner sur l’optimisation de l’appel de fonction a été amélioré avec un nouveau protocole d’exécution nommé vectorcall
. Pour le moment, c’est de la cuisine interne. Python 3.9 devrait exposer davantage d’optimisation possible dans le code Python.
On peut désormais spécifier un caractère Unicode par son nom dans les expressions rationnelles avec \N{NOM UNICODE}
plutôt que par son code ou son encodage UTF-8. Ainsi, r'\N{EM DASH}'
équivaut à '—'
ou '\u2014'
. La notation \N
permet d’utiliser le mode brut r''
incompatible avec \uXXXX
.
python -m json.tool
accepte désormais un objet JSON par ligne avec l’option --json-line
. Ce cas est courant avec les journaux au format JSON.
Il reste moult nouveautés et changements à découvrir. N’hésitez pas à consulter la longue page des nouveautés de cette version 3.8, notamment la section sur les API obsolètes retirées et les conseils de migration. Bonne découverte !