Les nouveautés de Python 3.10

Version

3.10.0

Date

décembre 06, 2021

Rédacteur

Pablo Galindo Salgado

Cet article explique les nouvelles fonctionnalités de Python 3.10 par rapport à la version 3.9.

Pour plus de détails, voir le changelog.

Résumé – Points forts de la publication

Nouvelles fonctionnalités de syntaxe :

  • PEP 634, Filtrage par motifs structurels : spécification ;

  • PEP 635, Filtrage par motifs structurels : motivation et justification ;

  • PEP 636, Filtrage par motifs structurels : tutoriel ;

  • bpo-12782, Les gestionnaires de contextes entre parenthèses sont maintenant autorisés.

Nouvelles fonctionnalités dans la bibliothèque standard :

  • PEP 618, ajout de la vérification optionnelle de taille dans zip.

Améliorations de l'interpréteur :

  • PEP 626, numéros de lignes précis pour le débogage et les autres outils.

Nouvelles fonctionnalités de typage :

  • PEP 604, autorise l'écriture d'union de types sous la forme X | Y ;

  • PEP 613, alias de types explicites ;

  • PEP 612, variables de spécification de paramètres.

Obsolescences, retraits ou restrictions :

  • PEP 644, mise à jour de la version minimale d'OpenSSL à 1.1.1 ;

  • PEP 632, obsolescence du module distutils ;

  • PEP 623, obsolescence et préparation du retrait du membre wstr de PyUnicodeObject ;

  • PEP 624, retrait des API d'encodage Py_UNICODE ;

  • PEP 597, ajout de l'EncodingWarning optionnel

Nouvelles fonctionnalités

Gestionnaires de contextes entre parenthèses

Il est maintenant possible de mettre les gestionnaires de contexte entre parenthèses pour les répartir sur plusieurs lignes. Ceci permet le formatage d'une longue série de gestionnaires de contexte sur plusieurs lignes comme ce qui était préalablement possible avec les instructions d'importation. Par exemple, tous ces blocs sont maintenant valides :

with (CtxManager() as example):
    ...

with (
    CtxManager1(),
    CtxManager2()
):
    ...

with (CtxManager1() as example,
      CtxManager2()):
    ...

with (CtxManager1(),
      CtxManager2() as example):
    ...

with (
    CtxManager1() as example1,
    CtxManager2() as example2
):
    ...

il est aussi possible d'utiliser une virgule en fin de ligne à la fin du groupe entre parenthèses :

with (
    CtxManager1() as example1,
    CtxManager2() as example2,
    CtxManager3() as example3,
):
    ...

Cette nouvelle syntaxe utilise la capacité non-LL(1) du nouvel analyseur syntaxique. Voir PEP 617 pour plus de détails.

(contribution de Guido van Rossum, Pablo Galindo et Lysandros Nikolaou dans bpo-12782 et bpo-40334).

Meilleurs messages d'erreurs

SyntaxError

Pendant l'analyse syntaxique de code qui contient des parenthèses ou autres balises ouvrantes et fermantes, l'interpréteur inclut maintenant l'emplacement de la balise ou parenthèse non fermée plutôt que d'afficher SyntaxError: unexpected EOF while parsing ou d'indiquer un emplacement incorrect. Par exemple, considérez le code suivant (remarquez l'accolade '{' non-fermée) :

expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4,
            38: 4, 39: 4, 45: 5, 46: 5, 47: 5, 48: 5, 49: 5, 54: 6,
some_other_code = foo()

Les versions précédentes de l’interpréteur indiquaient des emplacements qui portaient à confusion pour l'erreur de syntaxe :

File "example.py", line 3
    some_other_code = foo()
                    ^
SyntaxError: invalid syntax

mais dans Python 3.10, une erreur plus informative est levée :

File "example.py", line 1
    expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4,
               ^
SyntaxError: '{' was never closed

De façon similaire, les erreurs impliquant des chaînes littérales non-fermées (avec simples ou triples apostrophes) pointent maintenant vers le début de la chaîne plutôt de mentionner la fin de ligne ou la fin du fichier.

Ces améliorations sont inspirées par un travail préalable sur l'interpréteur PyPy

(contribution de Pablo Galindo dans bpo-42864 et Batuhan Taskaya dans bpo-40176).

Les exceptions SyntaxError levées par l'interpréteur soulignent maintenant toute la portée de l'expression qui constitue l'erreur de syntaxe plutôt que seulement la position où le problème a été détecté. De cette façon, plutôt que d'afficher (avant Python 3.10) :

>>> foo(x, z for z in range(10), t, w)
  File "<stdin>", line 1
    foo(x, z for z in range(10), t, w)
           ^
SyntaxError: Generator expression must be parenthesized

Python 3.10 affiche maintenant l'exception comme ceci :

>>> foo(x, z for z in range(10), t, w)
  File "<stdin>", line 1
    foo(x, z for z in range(10), t, w)
           ^^^^^^^^^^^^^^^^^^^^
SyntaxError: Generator expression must be parenthesized

Cette amélioration est une contribution de Pablo Galindo dans bpo-43914.

Un nombre considérable de nouveaux messages spécialisés pour les exceptions SyntaxError a été incorporé. Certains des plus notables sont :

  • : manquant avant les blocs :

    >>> if rocket.position > event_horizon
      File "<stdin>", line 1
        if rocket.position > event_horizon
                                          ^
    SyntaxError: expected ':'
    

    (contribution de Pablo Galindo dans bpo-42997) ;

  • Les n-uplets sans parenthèses dans les cibles de compréhensions :

    >>> {x,y for x,y in zip('abcd', '1234')}
      File "<stdin>", line 1
        {x,y for x,y in zip('abcd', '1234')}
         ^
    SyntaxError: did you forget parentheses around the comprehension target?
    

    (contribution de Pablo Galindo dans bpo-43017) ;

  • virgules manquantes dans les littéraux de collections et entre les expressions ;

    >>> items = {
    ... x: 1,
    ... y: 2
    ... z: 3,
      File "<stdin>", line 3
        y: 2
           ^
    SyntaxError: invalid syntax. Perhaps you forgot a comma?
    

    (contribution de Pablo Galindo dans bpo-43822) ;

  • types multiples d'Exception sans parenthèses :

    >>> try:
    ...     build_dyson_sphere()
    ... except NotEnoughScienceError, NotEnoughResourcesError:
      File "<stdin>", line 3
        except NotEnoughScienceError, NotEnoughResourcesError:
               ^
    SyntaxError: multiple exception types must be parenthesized
    

    (contribution de Pablo Galindo dans bpo-43149) ;

  • : et valeurs manquantes dans les littéraux de dictionnaires :

    >>> values = {
    ... x: 1,
    ... y: 2,
    ... z:
    ... }
      File "<stdin>", line 4
        z:
         ^
    SyntaxError: expression expected after dictionary key and ':'
    
    >>> values = {x:1, y:2, z w:3}
      File "<stdin>", line 1
        values = {x:1, y:2, z w:3}
                            ^
    SyntaxError: ':' expected after dictionary key
    

    (contribution de Pablo Galindo dans bpo-43823) ;

  • blocs try sans blocs except ou finally :

    >>> try:
    ...     x = 2
    ... something = 3
      File "<stdin>", line 3
        something  = 3
        ^^^^^^^^^
    SyntaxError: expected 'except' or 'finally' block
    

    (contribution de Pablo Galindo dans bpo-44305) ;

  • utilisation de = au lieu de == dans les comparaisons :

    >>> if rocket.position = event_horizon:
      File "<stdin>", line 1
        if rocket.position = event_horizon:
                           ^
    SyntaxError: cannot assign to attribute here. Maybe you meant '==' instead of '='?
    

    (contribution de Pablo Galindo dans bpo-43797)

  • utilisation de * dans les chaînes formatées (f-strings) :

    >>> f"Black holes {*all_black_holes} and revelations"
      File "<stdin>", line 1
        (*all_black_holes)
         ^
    SyntaxError: f-string: cannot use starred expression here
    

    (contribution de Pablo Galindo dans bpo-41064).

IndentationError

Plusieurs exceptions IndentationError ont maintenant plus de contexte concernant le genre de bloc qui attendait une indentation. Ceci inclut l'emplacement de l'instruction :

>>> def foo():
...    if lel:
...    x = 2
  File "<stdin>", line 3
    x = 2
    ^
IndentationError: expected an indented block after 'if' statement in line 2

AttributeError

À l'impression d'une AttributeError, PyErr_Display() offre des suggestions de noms d'attributs similaires dans l'objet pour lequel l'exception a été levée :

>>> collections.namedtoplo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'collections' has no attribute 'namedtoplo'. Did you mean: namedtuple?

(contribution de Pablo Galindo dans bpo-38530).

Avertissement

notez que ceci ne fonctionne pas si PyErr_Display() n'est pas appelée pour afficher l'erreur, ce qui est le cas si une fonction d'affichage d'erreur personnalisée est utilisée. C'est un scénario typique avec certains interpréteurs interactifs comme IPython.

NameError

Quand elle affiche une NameError levée par l'interpréteur, PyErr_Display() offre des suggestions de variables qui ont un nom similaire dans la fonction de laquelle l’exception a été levée :

>>> schwarzschild_black_hole = None
>>> schwarschild_black_hole
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'schwarschild_black_hole' is not defined. Did you mean: schwarzschild_black_hole?

(contribution de Pablo Galindo dans bpo-38530).

Avertissement

notez que ceci ne fonctionne pas si PyErr_Display() n'est pas appelée pour afficher l'erreur, ce qui est le cas si une fonction d'affichage d'erreur personnalisée est utilisée. C'est un scénario typique avec certains interpréteurs interactifs comme IPython.

PEP 626 : numéros de lignes précis pour le débogage et les autres outils

La PEP 626 apporte des numéros de lignes plus précis pour le débogage, le profilage et les outils de mesure de couverture. Les événements de traçage, avec les numéros de ligne corrects, sont générés pour toutes les lignes de code exécutées et seulement pour celles-ci.

L'attribut f_lineno des objets cadres contient dorénavant le numéro de ligne attendu.

L'attribut co_lnotab des objets code est obsolète et sera retiré dans 3.12. Tout code qui doit convertir d'un décalage (offset) vers des numéros de ligne doit plutôt utiliser la nouvelle méthode co_lines().

PEP 634 : filtrage par motifs structurels

Le filtrage par motifs a été ajouté sous la forme d'une instruction match et d'instructions case pour les motifs avec des actions associées. Les motifs filtrent des séquences, des dictionnaires, des types de données et des instances de classes. Le filtrage par motifs permet aux programmes d'extraire de l'information de types de données complexes, faire du branchement selon la structure des données et réaliser des actions spécifiques en fonction des différentes formes des données.

Syntaxe et opérations

La syntaxe générique du filtrage par motifs est :

match subject:
    case <pattern_1>:
        <action_1>
    case <pattern_2>:
        <action_2>
    case <pattern_3>:
        <action_3>
    case _:
        <action_wildcard>

Une instruction match prend une expression et compare successivement sa valeur à différents filtres qui sont donnés comme un ou plusieurs blocs case. Plus précisément, le filtrage par motifs s'effectue par :

  1. l'utilisation de données qui ont un type et une forme (ici subject) ;

  2. l'évaluation de subject dans une instruction match ;

  3. l'application de chaque filtre sur subject dans des instructions case de haut en bas jusqu'à ce qu'un appariement soit confirmé ;

  4. l’exécution de l'action associée au filtre s'il y a appariement ;

  5. s'il n'y a aucun appariement et que le dernier case est un filtre attrape-tout _, l'action correspondante est exécutée. S'il n'y a aucun appariement ni filtre attrape-tout, le bloc match n'effectue aucune opération.

Approche déclarative

Le filtrage par motifs est peut-être connu des lecteurs par l'intermédiaire des langages C, Java ou JavaScript (et plusieurs autres langages), avec l'appariement simple d'un sujet (objet de données) à un littéral (filtre) avec l'instruction switch. Souvent, l'instruction switch est utilisée pour comparer des objets ou expressions à des instructions case qui contiennent des littéraux.

Des exemples plus puissants de filtrage par motifs sont présents dans des langages tels que Scala et Elixir. Avec le filtrage par motifs structurels, l'approche est « déclarative » et énonce les conditions (les motifs) pour apparier les données.

Bien qu'une série d'instructions « impératives » utilisant des instructions « if » imbriquées puisse être utilisée pour accomplir quelque chose de similaire au filtrage par motifs structurels, ceci est moins clair que l'approche « déclarative ». Cette dernière énonce les conditions à remplir pour réaliser un appariement grâce à ses filtres sur des motifs explicites. Bien que le filtrage par motifs structurels puisse être utilisé dans sa forme la plus simple pour comparer une variable à un littéral dans une instruction case, son intérêt réel en Python réside dans son traitement du sujet selon son type et sa forme.

Filtre simple : apparier à un littéral

Regardons cet exemple en tant que filtrage par motif dans sa forme la plus simple : une valeur, le sujet, est comparée à (ou « filtrée par ») plusieurs littéraux, les motifs. Dans l'exemple ci-dessous, status est le sujet de l'instruction match. Les filtres sont chacune des instructions case, où les littéraux représentent les codes de status des requêtes. Les actions associées au case sont exécutés suite à un appariement :

def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 404:
            return "Not found"
        case 418:
            return "I'm a teapot"
        case _:
            return "Something's wrong with the internet"

Si on passe 418 à status dans la fonction ci-haut, elle renvoie "I'm a teapot". Avec 500, l'instruction case qui contient _ apparie comme attrape-tout et la fonction renvoie "Something's wrong with the internet". Prenez note que dans le dernier bloc, le nom de variable, _ agit comme un attrape-tout et garantit que le sujet sera toujours apparié. L'utilisation de _ est optionnelle.

Vous pouvez combiner plusieurs littéraux dans un seul filtre en utilisant | (qui se lit « ou ») :

case 401 | 403 | 404:
    return "Not allowed"
Comportement sans l'attrape-tout

Modifions l'exemple ci-haut en enlevant le dernier bloc case. Il devient :

def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 404:
            return "Not found"
        case 418:
            return "I'm a teapot"

Sans l'utilisation de _ dans une instruction case, il est possible de ne pas avoir d'appariement. Dans ce cas, il ne se passe rien. Par exemple, si 500 est passé à status, aucune opération n'est effectuée.

Filtres avec un littéral et une variable

Les motifs des filtres peuvent prendre une forme similaire aux affectations multiples et un filtre peut être utilisé pour lier plus d'une variable. Dans cet exemple, un point peut être dissocié entre son abscisse et son ordonnée :

# point is an (x, y) tuple
match point:
    case (0, 0):
        print("Origin")
    case (0, y):
        print(f"Y={y}")
    case (x, 0):
        print(f"X={x}")
    case (x, y):
        print(f"X={x}, Y={y}")
    case _:
        raise ValueError("Not a point")

Le motif du premier filtre comporte deux littéraux, (0, 0), et peut être vu comme une extension du filtre sur un littéral montré plus haut. Les motifs des deux filtres suivants regroupent un littéral et une variable. De plus, la variable est liée à la valeur provenant du sujet (point). Le motif du quatrième filtre capture deux valeurs, ce qui le rend conceptuellement similaire à l'affectation multiple : (x, y) = point.

Filtres et classes

Si vous utilisez des classes pour structurer vos données, vous pouvez utiliser le nom de la classe suivie d'une liste d'arguments comme motif de filtre. Ceci ressemble à un appel du constructeur. Ce filtre peut capturer les attributs de la classe dans des variables :

class Point:
    x: int
    y: int

def location(point):
    match point:
        case Point(x=0, y=0):
            print("Origin is the point's location.")
        case Point(x=0, y=y):
            print(f"Y={y} and the point is on the y-axis.")
        case Point(x=x, y=0):
            print(f"X={x} and the point is on the x-axis.")
        case Point():
            print("The point is located somewhere else on the plane.")
        case _:
            print("Not a point")
Filtres avec arguments positionnels

Vous pouvez utiliser les arguments positionnels avec un certain nombre de classes natives qui définissent l'ordre de leurs attributs, notamment les classes de données (dataclasses). Vous pouvez aussi spécifier la position des attributs quand ils sont utilisés dans les filtres en définissant l'attribut spécial __match_args__ dans vos classes. Par exemple, le mettre à ("x", "y") rend tous les filtres ci-dessous équivalents (en particulier, tous provoquent la liaison de l'attribut y à la variable var) :

Point(1, var)
Point(1, y=var)
Point(x=1, y=var)
Point(y=var, x=1)

Filtres imbriqués

Les filtres peuvent être imbriqués de façon arbitraire. Par exemple, si nous avons une courte liste de points, elle peut être appariée comme ceci :

match points:
    case []:
        print("No points in the list.")
    case [Point(0, 0)]:
        print("The origin is the only point in the list.")
    case [Point(x, y)]:
        print(f"A single point {x}, {y} is in the list.")
    case [Point(0, y1), Point(0, y2)]:
        print(f"Two points on the Y axis at {y1}, {y2} are in the list.")
    case _:
        print("Something else is found in the list.")

Filtres complexes et attrape-tout

Jusqu'à maintenant, les exemples ont utilisé _ seul dans la dernière instruction case. Un attrape-tout peut être utilisé dans un filtre plus complexe tel que ('error', code, _). Par exemple :

match test_variable:
    case ('warning', code, 40):
        print("A warning has been received.")
    case ('error', code, _):
        print(f"An error {code} occurred.")

Dans l'exemple précédent, test_variable s'apparie à ('error', code, 100) et à ('error', code, 800).

Garde

On peut ajouter une clause if à un filtre, ce qu'on appelle une « garde ». Si la garde s'évalue à faux, match poursuit avec la tentative d'appariement du prochain bloc case. Notez que la capture de valeur se produit avant l'évaluation de la garde :

match point:
    case Point(x, y) if x == y:
        print(f"The point is located on the diagonal Y=X at {x}.")
    case Point(x, y):
        print(f"Point is not on the diagonal.")

Autres fonctionnalités importantes

Plusieurs autres fonctionnalités importantes :

  • Comme dans les affectations multiples, les motifs de filtres qui sont des n-uplets ou des listes sont totalement équivalents et autorisent tous les types de séquences. Techniquement, le sujet doit être une séquence. Ainsi, exception importante, les filtres n'autorisent pas les itérateurs. Aussi, pour prémunir d'une erreur commune, les filtres de séquences n'autorisent pas les chaînes ;

  • les filtres de séquence peuvent faire intervenir l'affectation étoilée : [x, y, *reste] ou (x, y, *reste) ont le même sens que dans une affectation avec =. Le nom de variable après l'étoile peut aussi être l'attrape-tout _. Ainsi, (x, y, *_) est un motif de filtre qui reconnaît les séquences à deux éléments ou plus, en capturant les deux premiers et en ignorant le reste ;

  • il existe les filtres d'association, qui ressemblent syntaxiquement aux dictionnaires. Par exemple, le filtre {"bande_passante": b, "latence": l} extrait les valeurs des clés "bande_passante" et "latence" dans un dictionnaire. Contrairement aux filtres de séquence, les clés absentes du filtre sont ignorées et le filtre réussit tout de même. L'affectation double-étoilée (**reste) fonctionne aussi (cependant, **_ serait redondant et n'est donc pas permis) ;

  • on peut capturer la valeur d'une partie du motif d'un filtre avec le mot-clé as, par exemple :

    case (Point(x1, y1), Point(x2, y2) as p2): ...
    

    Ceci lie x1, y1, x2, y2 comme attendu sans la clause as, et lie p2 à l’entièreté du second élément du sujet ;

  • la plupart des littéraux sont comparés par égalité. Néanmoins, les singletons True, False et None sont comparés par identité ;

  • les filtres peuvent contenir des noms qui se réfèrent à des constantes. Ces noms doivent impérativement être qualifiés (contenir au moins un point) pour ne pas être interprétés comme des variables de capture :

    from enum import Enum
    class Color(Enum):
        RED = 0
        GREEN = 1
        BLUE = 2
    
    match color:
        case Color.RED:
            print("I see red!")
        case Color.GREEN:
            print("Grass is green")
        case Color.BLUE:
            print("I'm feeling the blues :(")
    

Pour la spécification complète, voir la PEP 634. La motivation et la justification des choix sont dans la PEP 635, et un tutoriel plus élaboré se trouve dans la PEP 636.

EncodingWarning et option encoding="locale" optionnels

L'encodage par défaut de TextIOWrapper et de open() dépend de la plateforme et des paramètres régionaux. Comme UTF-8 est utilisé sur la plupart des plateformes Unix, ne pas spécifier l'option encoding pour ouvrir des fichiers UTF-8 est une erreur courante. Par exemple :

# BUG: "rb" mode or encoding="utf-8" should be used.
with open("data.json") as f:
    data = json.load(f)

Pour trouver ce type de bogue, un EncodingWarning optionnel a été ajouté. Il est levé quand sys.flags.warn_default_encoding est True et quand l'encodage utilisé est celui défini par les paramètres régionaux.

L'option -X warn_default_encoding et la variable d’environnement PYTHONWARNDEFAULTENCODING ont été ajoutées pour activer cet avertissement.

Voir Text Encoding pour plus d'informations.

Autres changements au langage

  • Le type int a une nouvelle méthode int.bit_count(), qui renvoie le nombre de chiffres uns dans l’expansion binaire d'un entier donné, aussi connue sous le nom de chiffre de population (population count) (contribution de Niklas Fiekas dans bpo-29882).

  • Les vues renvoyées par dict.keys(), dict.values() et dict.items() ont maintenant toutes un attribut mapping qui donne un objet types.MappingProxyType encapsulant le dictionnaire original (contribution de Dennis Sweeney dans bpo-40890).

  • PEP 618 : la fonction zip() a maintenant un argument optionnel strict, utilisé pour demander que tous les itérables soient de même longueur.

  • Les fonctions d'extensions et les fonctions natives qui prennent des arguments entiers n'acceptent plus les Decimal, Fraction et autres objets qui ne peuvent pas être convertis en entiers sans perte de précision (par exemple ceux qui ont une méthode __int__() mais pas une méthode __index__()) (contribution de Serhiy Storchaka dans bpo-37999).

  • Si object.__ipow__() renvoie NotImplemented, l'opérateur va correctement se rabattre sur object.__pow__() et object.__rpow__() tel qu'attendu (contribution d'Alex Shkop dans bpo-38302).

  • Les expressions d'affectations peuvent maintenant être utilisées dans les littéraux d'ensembles, dans les compréhensions d'ensembles et dans les indices de séquences (mais pas dans les tranches).

  • Les fonctions ont un nouvel attribut __builtins__ qui est utilisé pour repérer les symboles natifs quand la fonction est exécutée, plutôt que de regarder dans __globals__['__builtins__']. L'attribut est initialisé à partir de __globals__["__builtins__"] s'il existe, ou des symboles natifs en cours autrement (contribution de Mark Shannon dans bpo-42990).

  • Deux nouvelles fonctions natives – aiter() et anext() – ont été ajoutées pour fournir les équivalents asynchrones de iter() et de next(), respectivement (contribution de Joshua Bronson, Daniel Pope et Justin Wang dans bpo-31861).

  • Les méthodes statiques (@staticmethod) et les méthodes de classes (@classmethod) héritent maintenant des attributs de méthodes (__module__, __name__, __qualname__, __doc__, __annotations__) et ont un nouvel attribut __wrapped__. De plus, les méthodes statiques sont maintenant appelables en tant que fonctions classiques (contribution de Victor Stinner dans bpo-43682).

  • Les annotations des cibles complexes (toutes cibles autre que simple name telles que définies dans la PEP 526) n'ont plus d'effet à l'exécution avec from __future__ import annotations (contribution de Batuhan Taskaya dans bpo-42737).

  • Les objets class et module créent maintenant paresseusement un dictionnaire d'annotations vide sur demande. Les dictionnaires d'annotations sont stockés dans le __dict__ de l'objet pour garder la retro-compatibilité. Cela renforce les bonnes pratiques relatives à __annotations__ ; pour plus d'information, voir Bonnes pratiques concernant les annotations (contribution de Larry Hastings dans bpo-43901).

  • Les annotations qui contiennent yield, yield from, await ou une expression nommée ne sont plus permises sous from __future__ import annotations à cause de leurs effets secondaires (contribution de Batuhan Taskaya dans bpo-42725).

  • L'utilisation de variables non liées, de super() et d'autres expressions qui peuvent changer le traitement de la table des symboles en tant qu'annotation n'ont plus d'effet sous from __future__ import annotations (contribution de Batuhan Taskaya dans bpo-42725).

  • Le hachage des valeurs NaN des types float et decimal.Decimal dépend maintenant de l'identité de l'objet. Préalablement, cette valeur de hachage était toujours 0 alors que les valeurs NaN ne sont pas égales entre elles. Cela pouvait potentiellement entrainer un temps d'exécution quadratique en raison des collisions excessives des valeurs de hachage lors de la création de dictionnaires et d'ensembles qui contiennent plusieurs NaN (contribution de Raymond Hettinger dans bpo-43475).

  • Une SyntaxError (plutôt qu'une NameError) sera levée quand la constante __debug__ est supprimée (contribution de Dong-hee Na dans bpo-45000).

  • Les exceptions SyntaxError ont maintenant des attributs end_lineno et end_offset. La valeur est None quand ils ne peuvent pas être déterminés (contribution de Pablo Galindo dans bpo-43914).

Nouveaux modules

  • Aucun pour le moment.

Modules améliorés

asyncio

Ajout de la méthode connect_accepted_socket() manquante (contribution d'Alex Grönholm dans bpo-41332).

argparse

L'expression "optional arguments" qui portait à confusion a été remplacée par "options" dans le message d'aide d'argparse. Certains tests devront être adaptés s'ils dépendent d'une comparaison exacte dans la sortie d'aide (contribution de Raymond Hettinger dans bpo-9694).

array

La méthode index() de la classe array.array a maintenant les paramètres optionnels start et stop (contribution d'Anders Lorentsen et de Zackery Spytz dans bpo-31956).

asynchat, asyncore, smtpd

Ces modules ont étés déclarés obsolètes dans leur documentation de modules depuis Python 3.6. Un DeprecationWarning au moment de l'importation est maintenant ajouté pour ces trois modules.

base64

Ajout de base64.b32hexencode() et de base64.b32hexdecode() pour prendre en charge l'encodage Base32 avec l'alphabet hexadécimal étendu.

bdb

Ajout de clearBreakpoints() pour supprimer tous les points d'arrêt (contribution d'Irit Katriel dans bpo-24160).

bisect

Ajout de la possibilité de fournir une fonction key aux API dans le module bisect (contribution de Raymond Hettinger dans bpo-4356).

codecs

Ajout d'une fonction codecs.unregister() pour désinscrire une fonction de recherche de codecs (contribution de Hai Shi dans bpo-41842).

collections.abc

L'attribut __args__ des génériques paramétrables de collections.abc.Callable est maintenant cohérent avec typing.Callable. Les génériques de collections.abc.Callable aplatissent maintenant les types des paramètres à l'instar de typing.Callable. Ceci veut dire que collections.abc.Callable[[int, str], str] aura un attribut __args__ de valeur (int, str, str) ; auparavant, il aurait été ([int, str], str). Pour permettre ce changement, types.GenericAlias peut être dérivée, et une sous-classe sera renvoyée lors de la surcharge du type collections.abc.Callable. Prenez note que TypeError sera levée pour des formes invalides de paramétrisation de collections.abc.Callable, ce qui aurait pu passer silencieusement dans Python 3.9 (contribution de Ken Jin dans bpo-42195).

contextlib

Ajout d'un gestionnaire de contexte contextlib.aclosing() pour fermer sécuritairement les générateurs asynchrones et les objets représentants des ressources libérées de façon asynchrone (contribution de Joongi Kim et John Belmonte dans bpo-41229).

Ajout d'un gestionnaire de contexte pour prendre en charge contextlib.nullcontext() (contribution de Tom Gringauz dans bpo-41543).

Ajout de AsyncContextDecorator pour prendre en charge les gestionnaires de contexte asynchrones en tant que décorateurs.

curses

Les fonctions de couleurs étendues ajoutées dans ncurses 6.1 sont utilisées de façon transparente par curses.color_content(), curses.init_color(), curses.init_pair() et curses.pair_content(). Une nouvelle fonction, curses.has_extended_color_support(), indique si la prise en charge des couleurs étendues est fournie par la bibliothèque ncurses sous-jacente (contribution de Jeffrey Kintscher et de Hans Petter Jansson dans bpo-36982).

Les constantes BUTTON5_* sont maintenant exposées dans le module curses si elles sont fournies par la bibliothèque curses sous-jacente (contribution de Zackery Spytz dans bpo-39273).

dataclasses

__slots__

Ajout du paramètre slots dans le décorateur dataclasses.dataclass() (contribution de Yurii Karabas dans bpo-42269).

Champs obligatoirement nommés

Les classes de données (dataclass) prennent maintenant en charge les champs obligatoirement nommés dans la méthode __init__ générée. Il y a plusieurs façons de spécifier les champs obligatoirement nommés.

Vous pouvez indiquer que tous les champs sont obligatoirement nommés :

from dataclasses import dataclass

@dataclass(kw_only=True)
class Birthday:
    name: str
    birthday: datetime.date

Les paramètres name et birthday sont tous deux obligatoirement nommés dans la méthode __init__ générée.

Pour chaque champ, vous pouvez indiquer s'il est obligatoirement nommé :

from dataclasses import dataclass

@dataclass
class Birthday:
    name: str
    birthday: datetime.date = field(kw_only=True)

Ici, seulement birthday est obligatoirement nommé. Si vous assignez kw_only sur un champ particulier, notez qu'il y a des règles concernant l'ordre des champs puisque les champs obligatoirement nommés doivent suivre les champs optionnellement nommés. Voir la documentation de dataclass pour plus de détails.

Vous pouvez aussi indiquer que tous les champs qui suivent un marqueur KW_ONLY sont obligatoirement nommés. Ceci sera probablement l'utilisation la plus commune :

from dataclasses import dataclass, KW_ONLY

@dataclass
class Point:
    x: float
    y: float
    _: KW_ONLY
    z: float = 0.0
    t: float = 0.0

Ici, z et t sont obligatoirement nommés, alors que x et y ne le sont pas (contribution d'Eric V. Smith dans bpo-43532).

distutils

Le paquet distutil est entièrement obsolète et sera retiré dans Python 3.12. Ses fonctionnalités pour spécifier la construction de paquets sont déjà complètement remplacées par les paquets tierce-parties setuptools et packaging. Les autres API régulièrement utilisées sont disponibles ailleurs dans la bibliothèque standard (tel que dans platform, shutil, subprocess ou sysconfig). Il n'est pas prévu de migrer d'autres fonctionnalités de distutils, aussi les applications qui utilisent d'autres fonctions du module doivent faire des copies privées du code. Voir la discussion dans la PEP 632.

La commande bdist_wininst qui est obsolète depuis Python 3.8 a été retirée. La commande bdist_wheel est maintenant recommandée pour distribuer des paquets binaires sous Windows (contribution de Victor Stinner dans bpo-42802).

doctest

Quand un module ne définit pas __loader__, __spec__.loader est utilisé (contribution de Brett Cannon dans bpo-42133).

encodings

La fonction encodings.normalize_encoding() ignore maintenant les caractères non ASCII (contribution de Hai Shi dans bpo-39337).

fileinput

Ajout des paramètres encoding et errors dans fileinput.input() et dans fileinput.FileInput (contribution d'Inada Naoki dans bpo-43712).

fileinput.hook_compressed() renvoie maintenant un objet TextIOWrapper quand mode est "r" et que le fichier est compressé, comme pour les fichiers non compressés (contribution d'Inada Naoki dans bpo-5758).

faulthandler

Le module faulthandler détecte maintenant si une erreur fatale s'est produite pendant un passage du ramasse-miettes (contribution de Victor Stinner dans bpo-44466).

gc

Ajout de fonctions de rappels d'audit pour gc.get_objects(), gc.get_referrers() et gc.get_referents() (contribution de Pablo Galindo dans bpo-43439).

glob

Ajout des paramètres root_dir et dir_fd dans glob() et dans iglob() pour permettre la spécification du répertoire racine utilisé pour la recherche (contribution de Serhiy Storchaka dans bpo-38144).

hashlib

La version minimale d'OpenSSL pour le module hashlib est maintenant 1.1.1 (contribution de Christian Heimes dans PEP 644 et dans bpo-43669).

Le module hashlib offre une prise en charge préliminaire pour OpenSSL 3.0.0 (contribution de Christian Heimes dans bpo-38820 et autres tickets).

Le repli vers la version en pur Python de pbkdf2_hmac() est obsolète. Dorénavant, PBKDF2-HMAC n'est disponible que si Python a été compilé avec la prise en charge d'OpenSSL (contribution de Christian Heimes dans bpo-43880).

hmac

L'implémentation interne du module hmac utilise maintenant HMAC d'OpenSSL (contribution de Christian Heimes dans bpo-40645).

IDLE et idlelib

IDLE invoque maintenant sys.excepthook() (lorsque lancé sans '-n'). Auparavant, les fonctions de rappel définies par l'utilisateur étaient ignorées (rustine par Ken Hilton dans bpo-43008).

Ce changement a été rétro-porté dans le cadre de la maintenance de 3.9.

Ajout d'une barre de côté à la console. Déplacement de l'invite de commande principale (>>>) vers cette barre. Ajout des invites secondaires (...) à la barre de côté. Le clic de gauche et le glisser optionnel sélectionnent une ou plusieurs lignes de texte, tout comme dans la barre de numéros de ligne de la fenêtre d'édition. Le clic droit après la sélection de lignes de texte affiche un menu contextuel pour copier avec invites ('copy with prompts'). Ceci combine les invites de la barre de côté avec le texte sélectionné. Cette option apparait aussi dans le menu contextuel pour le texte (contribution de Tal Einat dans bpo-37903).

Utilisation d'espaces plutôt que des tabulations pour indenter le code interactif. Ceci donne au code interactif la « bonne apparence ». Cette fonctionnalité est fortement corrélée à l'ajout de la barre de côté de la console (contribution de Terry Jan Reedy dans bpo-37892).

Il est prévu de rétro-porter ces changements de la console dans le cadre de la maintenance de 3.9.

Coloration des nouveaux mots clés ad-hoc match, case et _ dans les instructions de filtrage par motifs (pattern matching). Par contre, cette coloration n'est pas parfaite et elle sera incorrecte dans quelques rares cas, y-compris certains _ dans des instructions case (contribution de Tal Einat dans bpo-44010).

importlib.metadata

Équivalence de fonctionnalités avec importlib_metadata 4.6 (historique).

Les points d'entrée de importlib.metadata offrent maintenant une interface plus agréable pour choisir les points d'entrée par groupe et par nom par l'intermédiaire d'une nouvelle classe importlib.metadata.EntryPoints. Voir la rubrique Note sur la Compatibilité (Compatibility Note) dans la documentation du module importlib.metadata pour plus d'information sur son utilisation et ce qui devient obsolète.

Ajout de importlib.metadata.packages_distributions() pour résoudre les modules et paquets Python du niveau racine vers leur importlib.metadata.Distribution.

inspect

Quand un module ne définit pas __loader__, __spec__.loader est utilisé (contribution de Brett Cannon dans bpo-42133).

Ajout de inspect.get_annotations() qui calcule les annotations définies sur un objet de façon sécuritaire. Elle contourne les difficultés d’accéder aux annotations de différents types d'objets et présume très peu de l'objet examiné. inspect.get_annotations() peut également convertir pour vous les annotations contenues dans des chaînes de caractères en objets. inspect.get_annotations() est maintenant considérée comme la meilleure pratique pour accéder au dictionnaire d'annotations de tout objet qui prend en charge les annotations ; pour d'autre information sur les meilleures pratiques relatives aux annotations, voir Bonnes pratiques concernant les annotations. Dans le même esprit, inspect.signature(), inspect.Signature.from_callable() et inspect.Signature.from_function() appellent maintenant inspect.get_annotations() pour récupérer les annotations. Ceci veut dire que inspect.signature() et inspect.Signature.from_callable() peuvent maintenant convertir pour vous les annotations contenues dans des chaînes de caractères en objets (contribution de Larry Hastings dans bpo-43817).

linecache

Quand un module ne définit pas __loader__, __spec__.loader est utilisé (contribution de Brett Cannon dans bpo-42133).

os

Ajout de la prise en charge de VxWorks RTOS dans os.cpu_count() (contribution de Peixing Xin dans bpo-41440).

Ajout d'une nouvelle fonction os.eventfd() et des fonctions utilitaires associées pour encapsuler l'appel système eventfd2 sur Linux (contribution de Christian Heimes dans bpo-41001).

Ajout de os.splice() qui permet de déplacer des données entre deux descripteurs de fichiers sans copie entre les espaces noyau et utilisateur. Un des descripteurs de fichiers doit référencer un tube (pipe) (contribution de Pablo Galindo dans bpo-41625).

Add O_EVTONLY, O_FSYNC, O_SYMLINK and O_NOFOLLOW_ANY for macOS. (Contributed by Dong-hee Na in bpo-43106.)

os.path

os.path.realpath() accepte maintenant l'argument nommé strict. Lorsqu'il est True, une OSError est levée si le chemin n'existe pas ou si une boucle de liens symboliques est rencontrée (contribution de Barney Gale dans bpo-43757).

pathlib

Ajout de la prise en charge des tranches dans PurePath.parents (contribution de Joshua Cannon dans bpo-35498).

Ajout de la prise en charge de l'indiçage négatif dans PurePath.parents (contribution de Yaroslav Pankovych dans bpo-21041).

Ajout de la méthode Path.hardlink_to qui remplace link_to(). L'ordre des arguments de la nouvelle méthode est le même que symlink_to() (contribution de Barney Gale dans bpo-39950).

pathlib.Path.stat() et chmod() acceptent maintenant l'argument nommé follow_symlinks pour rester cohérent avec les fonctions correspondantes dans le module os (contribution de Barney Gale dans bpo-39906).

platform

Ajout de platform.freedesktop_os_release() pour récupérer l'information d'identification du système d'exploitation selon le fichier standard des versions de systèmes d'exploitations de freedesktop.org (contribution de Christian Heimes dans bpo-28468).

pprint

pprint.pprint() accepte maintenant le nouvel argument nommé underscore_numbers (contribution de sblondon dans bpo-42914).

pprint peut maintenant afficher élégamment les instances de dataclasses.dataclass (contribution de Lewis Gaul dans bpo-43080).

py_compile

Ajout de l'option de ligne de commande --quiet à l'interface de py_compile (contribution de Gregory Schevchenko dans bpo-38731).

pyclbr

Ajout d'un attribut end_lineno aux objets Function et Class dans l'arbre renvoyé par pyclbr.readline() et pyclbr.readline_ex(). Il complète l'attribut lineno déjà existant (contribution d'Aviral Srivastava dans bpo-38307).

shelve

Le module shelve utilise maintenant pickle.DEFAULT_PROTOCOL par défaut plutôt que le protocole 3 du module pickle à la création des objets shelf (contribution de Zackery Spytz dans bpo-34204).

statistics

Ajout des fonctions covariance(), correlation() (corrélation de Pearson) et linear_regression() (régression linéaire simple) (contribution de Tymoteusz Wołodźko dans bpo-38490).

site

Quand un module ne définit pas __loader__, __spec__.loader est utilisé (contribution de Brett Cannon dans bpo-42133).

socket

L'exception socket.timeout est maintenant un alias de TimeoutError (contribution de Christian Heimes dans bpo-42413).

Ajout d'une option pour créer des connecteurs (socket) MPTCP avec IPPROTO_MPTCP (contribution de Rui Cunha dans bpo-43571).

Ajout de l'option IP_RECVTOS pour récupérer la valeur des champs type of service (ToS) ou differentiated services code point (DSCP/ECN) (contribution de Georg Sauthoff dans bpo-44077).

ssl

La version minimale d'OpenSSL pour le module ssl est maintenant 1.1.1 (contribution de Christian Heimes dans PEP 644 et dans bpo-43669).

Le module ssl offre une prise en charge préliminaire pour OpenSSL 3.0.0 et la nouvelle option OP_IGNORE_UNEXPECTED_EOF (contribution de Christian Heimes dans bpo-38820, bpo-43794, bpo-43788, bpo-43791, bpo-43799, bpo-43920, bpo-43789 et bpo-43811).

Les fonctions obsolètes et l'accès aux constantes obsolètes lèvent maintenant un DeprecationWarning. ssl.SSLContext.options a options OP_NO_SSLv2 et OP_NO_SSLv3 définies par défaut ; par conséquent, il ne peut pas avertir si l'option est définie de nouveau. La section obsolescence contient la liste des fonctionnalités obsolètes (contribution de Christian Heimes dans bpo-43880).

La configuration du module ssl est plus sécuritaire par défaut. Les algorithmes de chiffrement sans confidentialité persistante (forward secrecy) et le code d'authentification de message (MAC) SHA-1 sont désactivés par défaut. Le niveau 2 de sécurité ne permet pas les clés faibles de moins de 112 bits pour RSA, DH et ECC. La version minimale du protocole TLS pour SSLContext est 1.2. La configuration est basée sur la recherche de Hynek Schlawack (contribution de Christian Heimes dans bpo-43998).

Les protocoles obsolètes SSL 3.0, TLS 1.0 et TLS 1.1 ne sont plus officiellement pris en charge. Python ne les bloque pas activement, mais les options de compilation d'OpenSSL, les configurations du système d'exploitation, les rustines des fabricants et les suites d'algorithmes de chiffrement peuvent empêcher l’établissement d'une connexion.

Ajout d'un paramètre timeout à la fonction ssl.get_server_certificate() (contribution de Zackery Spytz dans bpo-31870).

Le module ssl utilise les types du tas et l'initialisation multi-phase (contribution de Christian Heimes dans bpo-42333).

Ajout d'en nouveau drapeau de vérification VERIFY_X509_PARTIAL_CHAIN (contribution de l0x dans bpo-40849).

sqlite3

Ajout d'événements d'audit pour connect/handle(), enable_load_extension() et load_extension() (contribution d'Erlend E. Aasland dans bpo-43762).

sys

Ajout de l'attribut sys.orig_argv : la liste des arguments de ligne de commande originalement passée à l'exécutable Python (contribution de Victor Stinner dans bpo-23427).

Ajout de sys.stdlib_module_names qui contient la liste des noms des modules de la bibliothèque standard (contribution de Victor Stinner dans bpo-42955).

_thread

_thread.interrupt_main() prend maintenant l'argument optionnel signum : le numéro de signal à simuler (la valeur par défaut est toujours signal.SIGINT) (contribution d'Antoine Pitrou dans bpo-43356).

threading

Ajout des fonctions threading.gettrace() et threading.getprofile() pour récupérer les fonctions assignées par threading.settrace() et threading.setprofile() respectivement (contribution de Mario Corchero dans bpo-42251).

Ajout de threading.__excepthook__ pour permettre la récupération de threading.excepthook() au cas où elle serait affectée à une valeur incorrecte ou différente (contribution de Mario Corchero dans bpo-42308).

traceback

Les fonctions format_exception(), format_exception_only() et print_exception() peuvent maintenant prendre un objet exception en argument positionnel (contribution de Zackery Spytz et Matthias Bussonnier dans bpo-26389).

types

Les classes types.EllipsisType, types.NoneType et types.NotImplementedType sont ajoutées de nouveau. Elles fournissent un nouvel ensemble de types facilement interprétable par les vérificateurs de types (contribution de Bas van Beek dans bpo-41810).

typing

Pour les changements majeurs, voir Nouvelles fonctionnalités reliées aux indications de types.

Le comportement de typing.Literal a été changé pour être conforme avec la PEP 586 et pour correspondre au comportement des vérificateurs de types statiques défini dans la PEP.

  1. Literal dé-duplique maintenant les paramètres.

  2. La comparaison d'égalité entre objets Literal ne tient plus compte de l'ordre.

  3. Les comparaisons de Literal respectent maintenant les types. Par exemple, Literal[0] == Literal[False] était préalablement évaluée à True. Elle est maintenant False. Pour prendre en charge ce changement, le cache des types de l'implémentation interne peut maintenant différencier entre les types.

  4. Les objets Literal lèvent maintenant une exception TypeError pendant la comparaison d'égalité si au moins un de leurs paramètres n'est pas hachable. Notez que déclarer un Literal avec des paramètres non hachables ne lève pas d'erreur :

    >>> from typing import Literal
    >>> Literal[{0}]
    >>> Literal[{0}] == Literal[{False}]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unhashable type: 'set'
    

(contribution de Yurii Karabas dans bpo-42345).

Ajout d'une nouvelle fonction typing.is_typeddict() pour inspecter si une annotation est une typing.TypedDict (contribution de Patrick Reader dans bpo-41792).

Les sous-classes de typing.Protocol qui ne contiennent que des déclarations de variables de données vont maintenant lever une TypeError quand elles sont testées avec isinstance, sauf si elles sont décorées par runtime_checkable(). Auparavant, ces tests passaient silencieusement. Les utilisateurs doivent décorer leurs sous-classes avec le décorateur runtime_checkable() s'ils désirent les protocoles à l'exécution (contribution de Yurii Karabas dans bpo-38908).

Importer quoi que ce soit des sous-modules typing.io et typing.re émet maintenant un DeprecationWarning. Ces sous-modules sont obsolètes depuis Python 3.8 et seront retirés dans une version future de Python. Tout ce qui appartient à ces modules doit plutôt être importé directement du module typing (contribution de Sebastian Rittau dans bpo-38291).

unittest

Ajout d'une nouvelle méthode assertNoLogs() pour complémenter la méthode existante assertLogs() (contribution de Kit Yan Choi dans bpo-39385).

urllib.parse

Les versions préalables à Python 3.10 acceptaient les deux caractères ; et & comme séparateurs de paramètres de requêtes dans urllib.parse.parse_qs() et urllib.parse.parse_qsl(). Pour prévenir des failles de sécurité potentielles et pour respecter les dernières recommandations du W3C, ceci a été changé pour ne permettre qu'une seule clé de séparation, avec & par défaut. Ce changement affecte aussi l'implémentation interne de cgi.parse() et de cgi.parse_multipart() puisqu'elles utilisent les fonctions affectées. Pour plus de détails, voir la documentation respective de ces fonctions (contribution d'Adam Goldschmidt, de Senthil Kumaran et de Ken Jin dans bpo-42967).

La présence de caractères de saut de ligne ou de tabulation dans une URL permet certaines formes d'attaques. En conformité avec la spécification du WHATWG qui met à jour la RFC 3986, les caractères ASCII de saut de ligne \n, \r et de tabulation \t sont retirés des URL par l'analyseur dans urllib.parse pour contrer ces attaques. Le jeu de caractères à retirer est contrôlé par une nouvelle variable de module urllib.parse._UNSAFE_URL_BYTES_TO_REMOVE (voir bpo-43882).

xml

Ajout d'une classe LexicalHandler au module xml.sax.handler (contribution de Jonathan Gossage de Zackery Spytz dans bpo-35018).

zipimport

Ajout des méthodes relatives à la PEP 451 : find_spec(), zipimport.zipimporter.create_module() et zipimport.zipimporter.exec_module() (contribution de Brett Cannon dans bpo-42131).

Ajout de la méthode invalidate_caches() (contribution de Desmond Cheong dans bpo-14678).

Optimisations

  • Les constructeurs de str(), bytes() et bytearray() sont maintenant plus rapides (environ 30—40 % pour les petits objets) (contribution de Serhiy Storchaka dans bpo-41334).

  • Le module runpy importe maintenant moins de modules. Le temps de démarrage de la commande python3 -m module-name est en moyenne 1,4 fois plus rapide. Sur Linux python3 -I -m module-name importe 69 modules dans Python 3.9, alors qu'elle n'en importe que 51 (18 de moins) dans Python 3.10 (contribution de Victor Stinner dans bpo-41006 et dans bpo-41718).

  • L'instruction LOAD_ATTR utilise maintenant le mécanisme de cache par code d'opération. Elle est environ 36 % plus rapide pour les attributs ordinaires et 44 % plus rapide pour les slots (contribution de Pablo Galindo et de Yury Selivanov dans bpo-42093 et Guido van Rossum dans bpo-42927, basée sur des idées originalement mises en œuvre dans PyPy et dans MicroPython).

  • Lors de la construction de Python avec --enable-optimizations, -fno-semantic-interposition est maintenant ajouté aux lignes de commande de compilation et d'édition des liens. Ceci accélère les binaires de l'interpréteur Python créés avec --enable-shared et gcc jusqu'à 30 %. Voir cet article (en anglais) pour plus de détails (contribution de Victor Stinner et Pablo Galindo dans bpo-38980).

  • Ré-usinage du code assurant la gestion du tampon de sortie pour les modules bz2, lzma et zlib. Ajout de la fonction .readall() à la classe _compression.DecompressReader. La décompression bz2 est 1,09 à 1,17 fois plus rapide, la décompression lzma est 1,20 à 1,32 fois plus rapide, GzipFile.read(-1) est 1,11 à 1,18 fois plus rapide (contribution de Ma Lin, révision par Gregory P. Smith dans bpo-41486).

  • Quand les annotations sous forme de chaînes sont utilisées, les dictionnaires d'annotations ne sont plus créés à la création de la fonction. À la place, elles sont stockées dans des n-uplets de chaînes et l'objet fonction les convertit vers le dictionnaire d'annotations de façon paresseuse (c.-à-d. au besoin). Cette optimisation réduit de moitié le temps CPU nécessaire à la définition d'une fonction annotée (contribution de Yurii Karabas et Inada Naoki dans bpo-42202).

  • Les fonctions de recherche de sous-chaînes telles que str1 in str2 et str2.find(str1) peuvent utiliser maintenant l'algorithme « bidirectionnel » de recherche de chaînes Crochemore et Perrin pour éviter le comportement quadratique sur les longues chaînes (contribution de Dennis Sweeney dans bpo-41972).

  • Ajout d'une micro-optimisation dans _PyType_Lookup() pour améliorer la performance de la recherche du type des attributs dans le cache, dans le cas le plus commun où il est dans le cache. Ceci accélère l'interpréteur d'un facteur de 1,04 en moyenne (contribution de Dino Viehland dans bpo-43452).

  • Les fonctions natives suivantes prennent maintenant en charge la convention d'appel plus performante vectorcall définie dans la PEP 590 : map(), filter(), reversed(), bool() et float() (contribution de Dong-hee Na et Jeroen Demeyer dans bpo-43575, bpo-43287, bpo-41922, bpo-41873 et bpo-41870).

  • La performance de BZ2File est améliorée par le retrait d'un verrou RLock interne. Ceci rend BZ2File incompatible avec les fils d'exécutions multiples quand il y a plusieurs lecteurs ou écrivains concurrents, tout comme les classes équivalentes dans gzip et lzma qui l'ont toujours été (contribution de Inada Naoki dans bpo-43785).

Obsolescence

Removed

  • Removed special methods __int__, __float__, __floordiv__, __mod__, __divmod__, __rfloordiv__, __rmod__ and __rdivmod__ of the complex class. They always raised a TypeError. (Contributed by Serhiy Storchaka in bpo-41974.)

  • The ParserBase.error() method from the private and undocumented _markupbase module has been removed. html.parser.HTMLParser is the only subclass of ParserBase and its error() implementation was already removed in Python 3.5. (Contributed by Berker Peksag in bpo-31844.)

  • Removed the unicodedata.ucnhash_CAPI attribute which was an internal PyCapsule object. The related private _PyUnicode_Name_CAPI structure was moved to the internal C API. (Contributed by Victor Stinner in bpo-42157.)

  • Removed the parser module, which was deprecated in 3.9 due to the switch to the new PEG parser, as well as all the C source and header files that were only being used by the old parser, including node.h, parser.h, graminit.h and grammar.h.

  • Removed the Public C API functions PyParser_SimpleParseStringFlags, PyParser_SimpleParseStringFlagsFilename, PyParser_SimpleParseFileFlags and PyNode_Compile that were deprecated in 3.9 due to the switch to the new PEG parser.

  • Removed the formatter module, which was deprecated in Python 3.4. It is somewhat obsolete, little used, and not tested. It was originally scheduled to be removed in Python 3.6, but such removals were delayed until after Python 2.7 EOL. Existing users should copy whatever classes they use into their code. (Contributed by Dong-hee Na and Terry J. Reedy in bpo-42299.)

  • Removed the PyModule_GetWarningsModule() function that was useless now due to the _warnings module was converted to a builtin module in 2.6. (Contributed by Hai Shi in bpo-42599.)

  • Remove deprecated aliases to Classes de base abstraites de collections from the collections module. (Contributed by Victor Stinner in bpo-37324.)

  • The loop parameter has been removed from most of asyncio's high-level API following deprecation in Python 3.8. The motivation behind this change is multifold:

    1. This simplifies the high-level API.

    2. The functions in the high-level API have been implicitly getting the current thread's running event loop since Python 3.7. There isn't a need to pass the event loop to the API in most normal use cases.

    3. Event loop passing is error-prone especially when dealing with loops running in different threads.

    Note that the low-level API will still accept loop. See Changes in the Python API for examples of how to replace existing code.

    (Contributed by Yurii Karabas, Andrew Svetlov, Yury Selivanov and Kyle Stanley in bpo-42392.)

Porting to Python 3.10

This section lists previously described changes and other bugfixes that may require changes to your code.

Changes in the Python syntax

  • Deprecation warning is now emitted when compiling previously valid syntax if the numeric literal is immediately followed by a keyword (like in 0in x). In future releases it will be changed to syntax warning, and finally to a syntax error. To get rid of the warning and make the code compatible with future releases just add a space between the numeric literal and the following keyword. (Contributed by Serhiy Storchaka in bpo-43833).

Changes in the Python API

  • The etype parameters of the format_exception(), format_exception_only(), and print_exception() functions in the traceback module have been renamed to exc. (Contributed by Zackery Spytz and Matthias Bussonnier in bpo-26389.)

  • atexit: At Python exit, if a callback registered with atexit.register() fails, its exception is now logged. Previously, only some exceptions were logged, and the last exception was always silently ignored. (Contributed by Victor Stinner in bpo-42639.)

  • collections.abc.Callable generic now flattens type parameters, similar to what typing.Callable currently does. This means that collections.abc.Callable[[int, str], str] will have __args__ of (int, str, str); previously this was ([int, str], str). Code which accesses the arguments via typing.get_args() or __args__ need to account for this change. Furthermore, TypeError may be raised for invalid forms of parameterizing collections.abc.Callable which may have passed silently in Python 3.9. (Contributed by Ken Jin in bpo-42195.)

  • socket.htons() and socket.ntohs() now raise OverflowError instead of DeprecationWarning if the given parameter will not fit in a 16-bit unsigned integer. (Contributed by Erlend E. Aasland in bpo-42393.)

  • The loop parameter has been removed from most of asyncio's high-level API following deprecation in Python 3.8.

    A coroutine that currently looks like this:

    async def foo(loop):
        await asyncio.sleep(1, loop=loop)
    

    Should be replaced with this:

    async def foo():
        await asyncio.sleep(1)
    

    If foo() was specifically designed not to run in the current thread's running event loop (e.g. running in another thread's event loop), consider using asyncio.run_coroutine_threadsafe() instead.

    (Contributed by Yurii Karabas, Andrew Svetlov, Yury Selivanov and Kyle Stanley in bpo-42392.)

  • The types.FunctionType constructor now inherits the current builtins if the globals dictionary has no "__builtins__" key, rather than using {"None": None} as builtins: same behavior as eval() and exec() functions. Defining a function with def function(...): ... in Python is not affected, globals cannot be overridden with this syntax: it also inherits the current builtins. (Contributed by Victor Stinner in bpo-42990.)

Changes in the C API

  • The C API functions PyParser_SimpleParseStringFlags, PyParser_SimpleParseStringFlagsFilename, PyParser_SimpleParseFileFlags, PyNode_Compile and the type used by these functions, struct _node, were removed due to the switch to the new PEG parser.

    Source should be now be compiled directly to a code object using, for example, Py_CompileString(). The resulting code object can then be evaluated using, for example, PyEval_EvalCode().

    Specifically:

    • A call to PyParser_SimpleParseStringFlags followed by PyNode_Compile can be replaced by calling Py_CompileString().

    • There is no direct replacement for PyParser_SimpleParseFileFlags. To compile code from a FILE * argument, you will need to read the file in C and pass the resulting buffer to Py_CompileString().

    • To compile a file given a char * filename, explicitly open the file, read it and compile the result. One way to do this is using the io module with PyImport_ImportModule(), PyObject_CallMethod(), PyBytes_AsString() and Py_CompileString(), as sketched below. (Declarations and error handling are omitted.)

      io_module = Import_ImportModule("io");
      fileobject = PyObject_CallMethod(io_module, "open", "ss", filename, "rb");
      source_bytes_object = PyObject_CallMethod(fileobject, "read", "");
      result = PyObject_CallMethod(fileobject, "close", "");
      source_buf = PyBytes_AsString(source_bytes_object);
      code = Py_CompileString(source_buf, filename, Py_file_input);
      
    • For FrameObject objects, the f_lasti member now represents a wordcode offset instead of a simple offset into the bytecode string. This means that this number needs to be multiplied by 2 to be used with APIs that expect a byte offset instead (like PyCode_Addr2Line() for example). Notice as well that the f_lasti member of FrameObject objects is not considered stable: please use PyFrame_GetLineNumber() instead.

CPython bytecode changes

  • The MAKE_FUNCTION instruction now accepts either a dict or a tuple of strings as the function's annotations. (Contributed by Yurii Karabas and Inada Naoki in bpo-42202)

Build Changes

  • PEP 644: Python now requires OpenSSL 1.1.1 or newer. OpenSSL 1.0.2 is no longer supported. (Contributed by Christian Heimes in bpo-43669.)

  • The C99 functions snprintf() and vsnprintf() are now required to build Python. (Contributed by Victor Stinner in bpo-36020.)

  • sqlite3 requires SQLite 3.7.15 or higher. (Contributed by Sergey Fedoseev and Erlend E. Aasland bpo-40744 and bpo-40810.)

  • The atexit module must now always be built as a built-in module. (Contributed by Victor Stinner in bpo-42639.)

  • Add --disable-test-modules option to the configure script: don't build nor install test modules. (Contributed by Xavier de Gaye, Thomas Petazzoni and Peixing Xin in bpo-27640.)

  • Add --with-wheel-pkg-dir=PATH option to the ./configure script. If specified, the ensurepip module looks for setuptools and pip wheel packages in this directory: if both are present, these wheel packages are used instead of ensurepip bundled wheel packages.

    Some Linux distribution packaging policies recommend against bundling dependencies. For example, Fedora installs wheel packages in the /usr/share/python-wheels/ directory and don't install the ensurepip._bundled package.

    (Contributed by Victor Stinner in bpo-42856.)

  • Add a new configure --without-static-libpython option to not build the libpythonMAJOR.MINOR.a static library and not install the python.o object file.

    (Contributed by Victor Stinner in bpo-43103.)

  • The configure script now uses the pkg-config utility, if available, to detect the location of Tcl/Tk headers and libraries. As before, those locations can be explicitly specified with the --with-tcltk-includes and --with-tcltk-libs configuration options. (Contributed by Manolis Stamatogiannakis in bpo-42603.)

  • Add --with-openssl-rpath option to configure script. The option simplifies building Python with a custom OpenSSL installation, e.g. ./configure --with-openssl=/path/to/openssl --with-openssl-rpath=auto. (Contributed by Christian Heimes in bpo-43466.)

C API Changes

PEP 652: Maintaining the Stable ABI

The Stable ABI (Application Binary Interface) for extension modules or embedding Python is now explicitly defined. C API Stability describes C API and ABI stability guarantees along with best practices for using the Stable ABI.

(Contributed by Petr Viktorin in PEP 652 and bpo-43795.)

Nouvelles fonctionnalités

Porting to Python 3.10

  • The PY_SSIZE_T_CLEAN macro must now be defined to use PyArg_ParseTuple() and Py_BuildValue() formats which use #: es#, et#, s#, u#, y#, z#, U# and Z#. See Parsing arguments and building values and the PEP 353. (Contributed by Victor Stinner in bpo-40943.)

  • Since Py_REFCNT() is changed to the inline static function, Py_REFCNT(obj) = new_refcnt must be replaced with Py_SET_REFCNT(obj, new_refcnt): see Py_SET_REFCNT() (available since Python 3.9). For backward compatibility, this macro can be used:

    #if PY_VERSION_HEX < 0x030900A4
    #  define Py_SET_REFCNT(obj, refcnt) ((Py_REFCNT(obj) = (refcnt)), (void)0)
    #endif
    

    (Contributed by Victor Stinner in bpo-39573.)

  • Calling PyDict_GetItem() without GIL held had been allowed for historical reason. It is no longer allowed. (Contributed by Victor Stinner in bpo-40839.)

  • PyUnicode_FromUnicode(NULL, size) and PyUnicode_FromStringAndSize(NULL, size) raise DeprecationWarning now. Use PyUnicode_New() to allocate Unicode object without initial data. (Contributed by Inada Naoki in bpo-36346.)

  • The private _PyUnicode_Name_CAPI structure of the PyCapsule API unicodedata.ucnhash_CAPI has been moved to the internal C API. (Contributed by Victor Stinner in bpo-42157.)

  • Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix(), Py_GetProgramFullPath(), Py_GetPythonHome() and Py_GetProgramName() functions now return NULL if called before Py_Initialize() (before Python is initialized). Use the new Python Initialization Configuration API to get the Python Path Configuration.. (Contributed by Victor Stinner in bpo-42260.)

  • PyList_SET_ITEM(), PyTuple_SET_ITEM() and PyCell_SET() macros can no longer be used as l-value or r-value. For example, x = PyList_SET_ITEM(a, b, c) and PyList_SET_ITEM(a, b, c) = x now fail with a compiler error. It prevents bugs like if (PyList_SET_ITEM (a, b, c) < 0) ... test. (Contributed by Zackery Spytz and Victor Stinner in bpo-30459.)

  • The non-limited API files odictobject.h, parser_interface.h, picklebufobject.h, pyarena.h, pyctype.h, pydebug.h, pyfpe.h, and pytime.h have been moved to the Include/cpython directory. These files must not be included directly, as they are already included in Python.h: Include Files. If they have been included directly, consider including Python.h instead. (Contributed by Nicholas Sim in bpo-35134)

  • Use the Py_TPFLAGS_IMMUTABLETYPE type flag to create immutable type objects. Do not rely on Py_TPFLAGS_HEAPTYPE to decide if a type object is mutable or not; check if Py_TPFLAGS_IMMUTABLETYPE is set instead. (Contributed by Victor Stinner and Erlend E. Aasland in bpo-43908.)

  • The undocumented function Py_FrozenMain has been removed from the limited API. The function is mainly useful for custom builds of Python. (Contributed by Petr Viktorin in bpo-26241)

Obsolescence

  • The PyUnicode_InternImmortal() function is now deprecated and will be removed in Python 3.12: use PyUnicode_InternInPlace() instead. (Contributed by Victor Stinner in bpo-41692.)

Removed

  • Removed Py_UNICODE_str* functions manipulating Py_UNICODE* strings. (Contributed by Inada Naoki in bpo-41123.)

  • Removed PyUnicode_GetMax(). Please migrate to new (PEP 393) APIs. (Contributed by Inada Naoki in bpo-41103.)

  • Removed PyLong_FromUnicode(). Please migrate to PyLong_FromUnicodeObject(). (Contributed by Inada Naoki in bpo-41103.)

  • Removed PyUnicode_AsUnicodeCopy(). Please use PyUnicode_AsUCS4Copy() or PyUnicode_AsWideCharString() (Contributed by Inada Naoki in bpo-41103.)

  • Removed _Py_CheckRecursionLimit variable: it has been replaced by ceval.recursion_limit of the PyInterpreterState structure. (Contributed by Victor Stinner in bpo-41834.)

  • Removed undocumented macros Py_ALLOW_RECURSION and Py_END_ALLOW_RECURSION and the recursion_critical field of the PyInterpreterState structure. (Contributed by Serhiy Storchaka in bpo-41936.)

  • Removed the undocumented PyOS_InitInterrupts() function. Initializing Python already implicitly installs signal handlers: see PyConfig.install_signal_handlers. (Contributed by Victor Stinner in bpo-41713.)

  • Remove the PyAST_Validate() function. It is no longer possible to build a AST object (mod_ty type) with the public C API. The function was already excluded from the limited C API (PEP 384). (Contributed by Victor Stinner in bpo-43244.)

  • Remove the symtable.h header file and the undocumented functions:

    • PyST_GetScope()

    • PySymtable_Build()

    • PySymtable_BuildObject()

    • PySymtable_Free()

    • Py_SymtableString()

    • Py_SymtableStringObject()

    The Py_SymtableString() function was part the stable ABI by mistake but it could not be used, because the symtable.h header file was excluded from the limited C API.

    Use Python symtable module instead. (Contributed by Victor Stinner in bpo-43244.)

  • Remove PyOS_ReadlineFunctionPointer() from the limited C API headers and from python3.dll, the library that provides the stable ABI on Windows. Since the function takes a FILE* argument, its ABI stability cannot be guaranteed. (Contributed by Petr Viktorin in bpo-43868.)

  • Remove ast.h, asdl.h, and Python-ast.h header files. These functions were undocumented and excluded from the limited C API. Most names defined by these header files were not prefixed by Py and so could create names conflicts. For example, Python-ast.h defined a Yield macro which was conflict with the Yield name used by the Windows <winbase.h> header. Use the Python ast module instead. (Contributed by Victor Stinner in bpo-43244.)

  • Remove the compiler and parser functions using struct _mod type, because the public AST C API was removed:

    • PyAST_Compile()

    • PyAST_CompileEx()

    • PyAST_CompileObject()

    • PyFuture_FromAST()

    • PyFuture_FromASTObject()

    • PyParser_ASTFromFile()

    • PyParser_ASTFromFileObject()

    • PyParser_ASTFromFilename()

    • PyParser_ASTFromString()

    • PyParser_ASTFromStringObject()

    These functions were undocumented and excluded from the limited C API. (Contributed by Victor Stinner in bpo-43244.)

  • Remove the pyarena.h header file with functions:

    • PyArena_New()

    • PyArena_Free()

    • PyArena_Malloc()

    • PyArena_AddPyObject()

    These functions were undocumented, excluded from the limited C API, and were only used internally by the compiler. (Contributed by Victor Stinner in bpo-43244.)

  • The PyThreadState.use_tracing member has been removed to optimize Python. (Contributed by Mark Shannon in bpo-43760.)