Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Python 3.9 est disponible et s'accompagne de l'ajout des opérateurs "|" et "| =" aux dictionnaires
Ainsi que de la possibilité de construire des types génériques dans les collections standard

Le , par Stéphane le calme

23PARTAGES

12  0 
L'équipe en charge du développement du langage a annoncé la disponibilité de Python 3.9. Passons en revue quelques nouvelles fonctionnalités.

Nouvelles fonctionnalités

Ajout des opérateurs | et | = à dict

À partir des types de base (int, float, etc.) il est possible d’élaborer de nouveaux types qu’on appelle des types construits. Parmi les exemples de type construit figure le dictionnaire.

Les éléments d’une liste ou d’un tuple sont ordonnés et il est possible d'accéder à un élément grâce à sa position en utilisant un numéro qu’on appelle l’indice de l’élément. Un dictionnaire en Python va aussi permettre de rassembler des éléments, mais ceux-ci seront identifiés par une clé. On peut faire l’analogie avec un dictionnaire de français où on accède à une définition avec un mot.

Contrairement aux listes qui sont délimitées par des crochets, on utilise des accolades pour les dictionnaires.

Selon les responsables, les méthodes actuelles de fusion de deux dictionnaires présentent plusieurs inconvénients:
  • dict.update : d1.update(d2) modifie d1 sur place. e = d1.copy(); e.update(d2) n'est pas une expression et nécessite une variable temporaire
  • {** d1, ** d2} : peu de gens seraient capables de deviner ce que cela signifie la première fois qu'ils le voient, ou de le considérer comme la "manière évidente" de fusionner deux dictionnaires. De plus, {**d1, **d2} ignore les types des mappings et retourne toujours un dict. type(d1)({**d1, **d2}) ne fonctionne pas pour les sous-classes dict comme defaultdict qui a une __init__ method incompatible.

Aussi, dans cette version, les opérateurs de fusion (|) et de mise à jour (| =) ont été ajoutés à la classe dict intégrée. Ceux-ci viennent compléter les méthodes existantes dict.update et {** d1, ** d2} de fusion.

Exemple:

Code Python : Sélectionner tout
1
2
3
4
5
6
>>> x = {"key1": "value1 from x", "key2": "value2 from x"}
>>> y = {"key2": "value2 from y", "key3": "value3 from y"}
>>> x | y
{'key1': 'value1 from x', 'key2': 'value2 from y', 'key3': 'value3 from y'}
>>> y | x
{'key2': 'value2 from x', 'key3': 'value3 from y', 'key1': 'value1 from x'}

Nouvelles méthodes de chaîne pour supprimer les préfixes et les suffixes

str.removeprefix(prefix) et str.removesuffix(suffix) ont été ajoutés pour supprimer facilement un préfixe inutile ou un suffixe d'une chaîne. Les méthodes correspondantes bytes, bytearray, et collections.UserString ont aussi été ajoutées.

Sur des forums de discussion, plusieurs développeurs ont signalé être confus au sujet des méthodes str.lstrip et str.rstrip existantes. Ces développeurs s'attendent généralement au comportement de removeprefix et de removesuffix, mais ils sont surpris que le paramètre de lstrip soit interprété comme un ensemble de caractères et non comme une sous-chaîne. Ce problème signalé à plusieurs reprises semble indiquer que ces méthodes sont utiles. Les nouvelles méthodes permettent une redirection plus nette des utilisateurs vers le comportement souhaité.

La classe str intégrée gagnera deux nouvelles méthodes qui se comporteront comme suit :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
def removeprefix(self: str, prefix: str, /) -> str:
    if self.startswith(prefix):
        return self[len(prefix):]
    else:
        return self[:]
 
def removesuffix(self: str, suffix: str, /) -> str:
    # suffix='' should not call self[:-0].
    if suffix and self.endswith(suffix):
        return self[:-len(suffix)]
    else:
        return self[:]

Lorsque les arguments sont des instances de sous-classes str, les méthodes doivent se comporter comme si ces arguments avaient d'abord été forcés à des objets str de base, et la valeur de retour doit toujours être une str de base.

Les méthodes avec la sémantique correspondante seront ajoutées aux objets intégrés bytes et bytearray. Si b est un objet bytes ou bytearray, alors b.removeprefix() et b.removesuffix() accepteront tout objet de type bytes comme argument. Les deux méthodes seront également ajoutées aux collections.UserString, avec un comportement similaire.

Construction des types génériques dans les collections standard

Si vous avez travaillé avec les langages Java ou C#, vous connaissez la notion de types génériques. Ce sont généralement des collections qui peuvent être paramétrées avec le type qu'elles contiennent. Par exemple, en C#, vous pouvez définir une liste comme celle-ci : var exampleList = new List<string>(). Ce qui signifie que vous créez une liste de chaînes de caractères.

Maintenant, Python introduit ce genre de fonctionnalité dans le module de saisie. Fondamentalement, les outils ainsi que les vérificateurs de type et les linters sont modifiés pour reconnaître les collections standard comme des types génériques. Dans les annotations de type, vous pouvez désormais utiliser des types de collections intégrés tels que list et dict comme types génériques au lieu d'importer les types en majuscules correspondants (par exemple, List ou Dict) à partir de typing. Certains autres types de la bibliothèque standard sont également désormais génériques, par exemple queue.Queue. En bref, cette fonctionnalité supprime la nécessité d'une hiérarchie de types parallèle dans le module de saisie et facilite les annotations du programme.

Exemple :
Code Python : Sélectionner tout
1
2
3
def greet_all(names: list[str]) -> None:
    for name in names:
        print("Hello", name)

Nouvel analyseur

Python 3.9 utilise un nouvel analyseur, basé sur PEG au lieu de LL(1). Les performances du nouvel analyseur sont à peu près comparables à celles de l'ancien analyseur, mais le formalisme PEG est plus flexible que LL(1) lorsqu'il s'agit de concevoir de nouvelles fonctionnalités de langage. L'équipe fera appel à cette flexibilité à partir de Python 3.10.

Le module ast utilise le nouvel analyseur et produit le même AST que l'ancien analyseur.

Dans Python 3.10, l'ancien analyseur sera supprimé, de même que toutes les fonctionnalités qui en dépendent (principalement le module parser, qui est obsolète depuis longtemps). Dans Python 3.9 uniquement, vous pouvez revenir à l'analyseur LL(1) à l'aide d'un switch en ligne de commande (-X oldparser) ou d'une variable d'environnement (PYTHONOLDPARSER=1).

Autres changements au niveau du langage
  • __import__() lance désormais ImportError au lieu de ValueError, qui se produisait auparavant lorsqu'une importation relative dépassait son package de niveau supérieur.
  • Python obtient maintenant le chemin absolu du nom de fichier du script spécifié sur la ligne de commande (ex. : python3 script.py): l'attribut __file__ du module __main__ est devenu un chemin absolu, plutôt qu'un chemin relatif. Ces chemins restent désormais valides après la modification du répertoire courant par os.chdir().
  • "".replace("", s, n) retourne désormais s au lieu d'une chaîne de caractère vide pour tout n non vide.

Nouveaux modules

zoneinfo

Le module zoneinfo apporte la prise en charge de la base de données de fuseaux horaires IANA à la bibliothèque standard. Il ajoute zoneinfo.ZoneInfo, une implémentation concrète datetime.tzinfo soutenue par les données de fuseau horaire du système.

Exemple :
Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> from zoneinfo import ZoneInfo
>>> from datetime import datetime, timedelta
 
>>> # Daylight saving time
>>> dt = datetime(2020, 10, 31, 12, tzinfo=ZoneInfo("America/Los_Angeles"))
>>> print(dt)
2020-10-31 12:00:00-07:00
>>> dt.tzname()
'PDT'
 
>>> # Standard time
>>> dt += timedelta(days=7)
>>> print(dt)
2020-11-07 12:00:00-08:00
>>> print(dt.tzname())
PST

graphlib

Un nouveau module, graphlib, a été ajouté qui contient la classe graphlib.TopologicalSorter pour offrir des fonctionnalités pour effectuer le tri topologique des graphiques.

Modules améliorés

ast

Ce module s'accompagne de :
  • l'ajout d'une option indent à dump() qui lui permet de produire une sortie indentée multiligne ;
  • l'ajout de ast.unparse() comme fonction dans le module qui peut être utilisée pour décompresser (unparse) un objet ast.AST et produire une chaîne avec du code qui produirait un objet ast.AST équivalent lors de l'analyse ;
  • l'ajout de docstrings aux nœuds AST contenant la signature ASDL utilisée pour construire ce nœud.


asyncio

  • En raison de problèmes de sécurité importants, le paramètre reuse_address de asyncio.loop.create_datagram_endpoint() n'est plus pris en charge. Cela est dû au comportement de l'option de socket SO_REUSEADDR dans UDP.
  • Ce module s'accompagne de l'ajout d'une nouvelle coroutine shutdown_default_executor() qui planifie un arrêt de l'exécuteur par défaut qui attend que ThreadPoolExecutor termine sa fermeture. De plus, asyncio.run() a été mis à jour pour utiliser la nouvelle coroutine.
  • L'ajout de asyncio.PidfdChildWatcher, une implémentation de l'observateur enfant spécifique à Linux qui interroge les descripteurs de fichier de processus.
  • Ajout d'une nouvelle coroutine asyncio.to_thread(). Elle est principalement utilisée pour exécuter des fonctions liées aux E / S dans un thread séparé pour éviter de bloquer la boucle d'événements, et fonctionne essentiellement comme une version de haut niveau de run_in_executor() qui peut directement prendre des arguments de mot-clé.

Source : note de version

Voir aussi :

La popularité de Java continue de décliner et profite à Python qui se rapproche de plus en plus de la seconde place, selon l'édition d'octobre 2020 de l'index TIOBE
Microsoft annonce Playwright pour le langage Python, permettant de tester les applications Web et qui fonctionne dans tous les principaux navigateurs
Toutes les versions de Python inférieures à 3.6 sont maintenant en fin de vie, la version 3.9 sera livrée en octobre prochain et la version 3.10 un an après

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de transgohan
Expert éminent https://www.developpez.com
Le 06/10/2020 à 15:40
Python obtient maintenant le chemin absolu du nom de fichier du script spécifié sur la ligne de commande (ex: python3 script.py): l'attribut __file__ du module __main__ est devenu un chemin absolu, plutôt qu'un chemin relatif. Ces chemins restent désormais valides après la modification du répertoire courant par os.chdir().
Merci mille fois !
J'en ai l'utilité dans un projet et je dois systématiquement enregistrer la valeur de __file__ dans une variable avant d'exécuter une action qui pourrait avoir le malheur de faire un chdir...
Cela me paraît tellement aberrant de faire ainsi...
1  0 
Avatar de Fagus
Membre confirmé https://www.developpez.com
Le 07/10/2020 à 11:03
{** d1, ** d2} : peu de gens seraient capables de deviner ce que cela signifie la première fois qu'ils le voient,
Étrange choix en effet, on dirait une sorte de liste de pointeurs de pointeurs.
0  0