Les nouveautés de Python 3.9

Les nouveautés de Python 3.9

Python 3.9 est de sortie et dans cet article on découvre les principales nouveautés de cette version.

Publié le 09 septembre 2020 par Thibault
paceTemps de lecture estimé : 8 minutes

Python 3.9 apporte quelques nouveautés intéressantes qui permettent de rendre plus claires certaines opérations notamment sur les dictionnaires et les chaînes de caractères.

Opérateur de fusion de dictionnaires

La grande nouveauté de cette version, c'est l'apparition d'un nouvel opérateur destiné aux dictionnaires.

Cet opérateur permet de fusionner plus facilement deux dictionnaires.

Actuellement, il existe trois façons de fusionner deux dictionnaires.

Depuis la version 3.5 de Python, il est possible d'unpacker un dictionnaire, ce qui nous permet de faire :

d1 = {"a": 4, "b": 2, "c": 5}
d2 = {"a": 3, "d": 7, "e": 6}

# On crée un nouveau dictionnaire en utilisant la classe dict
d_fusion = dict(d1, **d2)  # {'a': 3, 'b': 2, 'c': 5, 'd': 7, 'e': 6}

Ou encore :

d1 = {"a": 4, "b": 2, "c": 5}
d2 = {"a": 3, "d": 7, "e": 6}

# On crée un nouveau dictionnaire en unpackant les deux dictionnaires
d_fusion = {**d1, **d2}  # {'a': 3, 'b': 2, 'c': 5, 'd': 7, 'e': 6}

Ces deux méthodes fonctionnent bien mais n'est pas très facile à comprendre pour un débutant.

L'unpacking est un concept avancé et même quand on le connaît, le code est assez obscur.

La dernière façon de faire consiste à utiliser la méthode update disponible sur les dictionnaires.

Le problème de cette méthode, c'est qu'elle agit directement sur le dictionnaire en question.

Si on souhaite donc créer un nouveau dictionnaire qui résulte de la fusion des deux premiers, il faut déjà utiliser la méthode copy pour faire une copie du premier dictionnaire.

d1 = {"a": 4, "b": 2, "c": 5}
d2 = {"a": 3, "d": 7, "e": 6}

d_fusion = d1.copy()  # On crée une copie du premier dictionnaire
d_fusion.update(d2)   # On met à jour notre copie du dictionnaire avec les données du dictionnaire d2

Là encore ça fonctionne, mais ça fait beaucoup d'opérations pour quelque chose qui devrait être simple à réaliser.

Avec Python 3.9, la fusion avec l'opérateur |

Pour réaliser cette opération de fusion, on peut donc avec Python 3.9 utiliser l'opérateur |.

d1 = {"a": 4, "b": 2, "c": 5}
d2 = {"a": 3, "d": 7, "e": 6}

d_fusion = d1 | d2  # {'a': 3, 'b': 2, 'c': 5, 'd': 7, 'e': 6}

Comme avec toutes les méthodes vues précédemment, les clés à droite remplaceront celles à gauche (la clé 'a' aura une valeur de 3, écrasant la valeur du dictionnaire d1).

Il est également possible de fusionner un dictionnaire sans avoir besoin d'en créer un nouveau, avec l'opérateur |= :

d1 = {"a": 4, "b": 2, "c": 5}
d2 = {"a": 3, "d": 7, "e": 6}

# On fusionne le dictionnaire d1 avec le dictionnaire d2.
d1 |= d2  # {'a': 3, 'b': 2, 'c': 5, 'd': 7, 'e': 6}

Personnellement j'aurais trouvé ça plus logique d'utiliser l'opérateur d'addition (+) plutôt que d'utiliser la barre verticale qui dans beaucoup de langage est le symbole de l'opérateur 'OR'.

Cette proposition a d'ailleurs été faite et rejetée (voir PEP584)

2 nouvelles méthodes pour supprimer un préfixe ou suffixe

Une des grandes forces de Python selon moi, c'est le nombre de méthodes qui existent pour réaliser des opérations de base sur différents types d'objet.

Il suffit de regarder Javascript pour se rendre compte que beaucoup de ces opérations réalisables facilement avec Python nécessitent dans d'autres langage d'user de nombreux split, join et autres méthodes de bas niveau.

Avec Python 3.9, deux nouvelles méthodes font leur apparition sur les chaînes de caractères : removeprefix et removesuffix.

Auparavant, il était possible de réaliser ces opérations grâce aux slices, mais là encore ce n'était pas très évident à comprendre pour un débutant :

# Pour enlever un préfixe
>>> s = "anticonformiste"
>>> s[len("anti"):]
"conformiste"

# Pour enlever un suffixe
>>> s = "anticonformiste"
>>> s[:-len("iste")]
"anticonform"

Avec les méthodes removeprefix et removesuffix :

# Pour enlever un préfixe
>>> s = "anticonformiste"
>>> s.removeprefix("anti")
"conformiste"

# Pour enlever un suffixe
>>> s = "anticonformiste"
>>> s.removesuffix("iste")
"anticonform"

Le code est tout de suite beaucoup plus clair et facile à écrire.

Cela évite de rajouter un commentaire pour expliquer ce que l'on fait avec les slices.

Comme souvent, un bon code est un code qui se documente tout seul.

C'est ce que nous permettent ce genre de méthodes très pratiques qui sont nombreuses avec Python.

À noter que ces méthodes n'agissent pas directement sur la chaîne de caractère. Et c'est logique, car une chaîne de caractères est immuable.

Si vous souhaitez que les modifications persistent, il faut soit écraser la variable existante soit en créer une nouvelle :

s = "anticonformiste"
# Avec une nouvelle variable
s_sans_prefix = s.removeprefix("anti")
# En assignant de nouveau sur la variable 's'
s = s.removeprefix("anti")

Nouveaux types génériques natifs

Il est maintenant possible d'utiliser les mots clés list et dict dans les annotations de type (type hinting en anglais).

Auparavant, il était nécessaire d'importer les types List et Dict depuis le module typing.

Il est donc maintenant possible de faire ce genre de code, sans avoir besoin d'importer quoi que ce soit :

def greet_all(names: list[str]) -> None:
    for name in names:
        print("Hello", name)

Les autres nouveautés

Voici les autres nouveautés de moindre importance (c'est subjectif) qu'apporte cette version 3.9 :

  • PEP 593, Annotations flexibles pour les fonctions et les variables.
  • PEP 602, Les versions de Python sortiront de façon plus régulière, selon un calendrier annuel.
  • PEP 615, Support pour le fuseau horaire IANA dans la librairie standard.
  • PEP 617, Nouvel analyseur syntaxique PEG pour CPython.

Également, plusieurs objets natifs de Python (range, tuple, set, frozenset, list et dict) sont maintenant plus rapides grâce à l'implémentation des vectorcall (introduit avec le PEP590).

Pour en savoir plus sur la date de sortie de Python 3.9 ainsi que toutes les nouveautés à propos de cette version, vous pouvez consulter cette page.