Meilleurs messages d'erreur dans l'analyseur
Lors de l'analyse de code contenant des parenthèses non fermées, l'interpréteur inclut désormais l'emplacement de la parenthèse non fermée au lieu d'afficher "SyntaxError: unexpected EOF" pendant l'analyse ou de pointer vers un emplacement incorrect. Les versions précédentes de l'interpréteur signalaient des endroits confus comme étant l'emplacement de l'erreur de syntaxe. De la même manière, les erreurs impliquant des littéraux de chaînes de caractères non fermées (entre guillemets simples et triples) pointent désormais vers le début de la chaîne au lieu de signaler EOF/EOL. Ces améliorations s'inspirent de travaux antérieurs dans l'interpréteur PyPy.
Correspondance structurelle de motifs
Malgré toute sa puissance et sa popularité, Python a longtemps manqué d'une forme de contrôle de flux que l'on trouve dans d'autres langues, une façon de prendre une valeur et de la faire correspondre "élégamment" à l'une des nombreuses conditions possibles. En C et C++, il s'agit de la construction de switch/case. En Rust, on parle de "correspondance de motifs" (pattern matching). En Python, les méthodes traditionnelles ne sont pas élégantes. L'une d'entre elles consiste à écrire une chaîne d'expressions if/elif/else.
L'autre consiste à stocker des valeurs à faire correspondre sous forme de clés dans un dictionnaire, puis à utiliser les valeurs pour effectuer une action. Par exemple, stocker une fonction sous forme de valeur et utiliser la clé ou une autre variable en entrée. Dans de nombreux cas, cela fonctionne bien, mais peut être lourd à construire et à maintenir. Après l'échec de nombreuses propositions visant à ajouter une syntaxe de type switch/case-like à Python, une proposition récente du créateur du langage Python Guido van Rossum et de plusieurs autres contributeurs a été acceptée pour Python 3.10 : structural pattern matching (correspondance structurelle de motifs).
La correspondance structurelle de motifs permet non seulement d'effectuer de simples correspondances de style switch/case, mais aussi de prendre en charge un plus large éventail de cas d'utilisation. Elle introduit l'instruction match/case et la syntaxe des motifs en Python. L'instruction match/case suit le même schéma de base que switch/case. Elle prend un objet, le teste par rapport à un ou plusieurs motifs et prend une mesure si elle trouve une correspondance.
Code : | Sélectionner tout |
1 2 3 4 5 6 7 | match command: case "quit": quit() case "reset": reset() case unknown_command: print (f"Unknown command '{unknown_command}') |
Il est également possible de capturer tout ou partie d'une correspondance et de la réutiliser. Dans le cas "unknown_command" de l'exemple ci-dessus, la valeur est "capturée" dans la variable "unknown_command" afin que l'on puisse la réutiliser.
L'évaluation différée des annotations devient la norme par défaut
Dans Python 3.7, l'évaluation différée des annotations a été ajoutée, pour être activée avec une directive d'importation d'annotations de __future__. Dans la version 3.10, c'est devenu le comportement par défaut, même sans cette directive. Avec ce comportement par défaut, toutes les annotations stockées dans __annotations__ seront des chaînes de caractères. Si nécessaire, les annotations peuvent être résolues à l'exécution en utilisant typing.get_type_hints(). En outre, la fonction inspect.signature() tentera désormais de résoudre les types et, en cas d'échec, elle se contentera d'afficher les annotations des chaînes de caractères.
Variables de spécification des paramètres
Deux nouvelles options visant à améliorer les informations fournies aux contrôleurs de type statiques pour Callable ont été ajoutées au module de saisie. La première est la variable de spécification des paramètres. Elles sont utilisées pour transmettre les types de paramètres d'un "callable" à un autre "callable", un modèle communément trouvé dans les fonctions d'ordre supérieur et les décorateurs. Auparavant, il n'y avait pas de moyen facile de taper la dépendance des types de paramètres d'une manière aussi précise. La deuxième option est le nouvel opérateur "Concatenate".
Il est utilisé en conjonction avec les variables de spécification des paramètres pour taper l'annotation d'un callable d'ordre supérieur qui ajoute ou supprime les paramètres d'un autre callable.
Annotation TypeAlias
La PEP 484 a introduit le concept des alias de types, en exigeant uniquement qu'il s'agisse d'affectations non annotées de haut niveau. Cette simplicité a parfois rendu difficile la distinction entre les alias de type et les affectations ordinaires pour les contrôleurs de type, en particulier lorsqu'il s'agit de références directes ou de types non valables. Le module de saisie comporte désormais une annotation spéciale TypeAlias pour déclarer plus explicitement les alias de type.
Gestionnaires de contexte entre parenthèses
L'utilisation de parenthèses pour la continuation à travers plusieurs lignes dans les gestionnaires de contexte est maintenant prise en charge. Cela permet de formater une longue collection de gestionnaires de contexte sur plusieurs lignes de la même manière que cela était possible auparavant avec les déclarations d'importation.
Autres changements
- le type int a une nouvelle méthode int.bit_count(), qui renvoie le nombre de "uns" dans l'expansion binaire d'un entier donné, également appelé nombre de population ;
- les vues renvoyées par dict.keys(), dict.values() et dict.items() ont maintenant toutes un attribut de mapping qui donne un objet types.MappingProxyType enveloppant le dictionnaire original ;
- la fonction zip() a maintenant un drapeau strict optionnel, utilisé pour exiger que tous les itérables aient une longueur égale ;
- les fonctions de construction et d'extension qui prennent des arguments entiers n'acceptent plus les décimales, les fractions et autres objets qui ne peuvent être convertis en entier qu'avec une perte (par exemple qui ont la méthode __int__(), mais n'ont pas la méthode __index__()) ;
- si object.__ipow__() renvoie NotImplemented, l'opérateur se rabattra correctement sur object.__pow__() et object.__rpow__() comme prévu ;
- les expressions d'affectation peuvent maintenant être utilisées sans parenthèses dans les littéraux et les compréhensions d'ensemble, ainsi que dans les index de séquence ;
- etc.
Modules améliorés
- argparse : l'expression trompeuse "optional arguments" a été remplacée par "options" dans l'aide d'argparse. Certains tests peuvent nécessiter une adaptation s'ils reposent sur une correspondance exacte de la sortie ;
- base64 : ajout de base64.b32hexencode() et base64.b32hexdecode() pour prendre en charge l'encodage Base32 avec l'alphabet hexadécimal étendu ;
- codecs : ajout de la fonction codecs.unregister() pour désenregistrer une fonction de recherche de codecs ;
- contextlib : ajout d'un gestionnaire de contexte contextlib.aclosing() pour fermer en toute sécurité les générateurs async et les objets représentant des ressources libérées de manière asynchrone. Il y a aussi l'ajout du support du gestionnaire de contexte asynchrone à contextlib.nullcontext() ;
- curses : les fonctions de couleur étendues ajoutées dans ncurses 6.1 seront utilisées de manière 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 le support étendu des couleurs est fourni par la bibliothèque ncurses sous-jacente. En outre, les constantes BUTTON5_* sont maintenant exposées dans le module curses si elles sont fournies par la bibliothèque curses sous-jacente ;
- distutils : l'ensemble du paquet distutils est déprécié, pour être supprimé dans Python 3.12 ;
- doctest : lorsqu'un module ne définit pas __loader__, l'on se rabat sur __spec__.loader ;
Optimisations
- les constructeurs str(), bytes() et bytearray() sont maintenant plus rapides (environ 30 à 40 % pour les petits objets) ;
- le module runpy importe maintenant moins de modules. Le temps de démarrage de la commande "python3 -m module-name" est en moyenne 1,3x plus rapide ;
- l'instruction LOAD_ATTR utilise désormais un nouveau mécanisme de "per opcode cache". Elle est maintenant environ 36 % plus rapide pour les attributs réguliers et 44 % plus rapide pour les slots ;
- les paramètres des fonctions et leurs annotations ne sont plus calculés au moment de l'exécution, mais plutôt au moment de la compilation. Ils sont stockés sous la forme d'un tuple de chaînes de caractères au niveau du bytecode. Il est maintenant environ 100 % plus rapide de créer une fonction avec des annotations de paramètres ;
- les fonctions de recherche de sous-chaîne telles que str1 dans str2 et str2.find(str1) utilisent maintenant parfois l'algorithme de recherche de chaîne "à deux voies" de Crochemore & Perrin pour éviter un comportement quadratique sur les longues chaînes ;
- etc.
Dépréciations
- à partir de cette version, il y aura un effort concerté pour commencer à nettoyer les anciennes sémantiques d'importation qui ont été conservées pour la compatibilité avec Python 2.7. Plus précisément, find_loader()/find_module() (remplacé par find_spec()), load_module() (remplacé par exec_module()), module_repr() (que le système d'importation prend en charge pour vous), l'attribut __package__ (remplacé par __spec__.parent), l'attribut __loader__ (remplacé par __spec__.loader), et l'attribut __cached__ (remplacé par __spec__.cached) seront lentement supprimés (ainsi que d'autres classes et méthodes dans importlib). Les avertissements d'importation et/ou de dépréciation seront augmentés selon le cas pour aider à identifier le code qui doit être mis à jour pendant cette transition ;
- tout l'espace de noms distutils est déprécié, pour être supprimé dans Python 3.12. ;
- les arguments non entiers de random.randrange() sont dépréciés. ValueError est dépréciée au profit de TypeError ;
- les différentes méthodes load_module() d'importlib sont documentées comme étant dépréciées depuis Python 3.6, mais vont maintenant aussi déclencher un DeprecationWarning. Utilisez plutôt exec_module() ;
- zimport.zipimporter.load_module() a été déprécié au profit de exec_module() ;
- l'utilisation de load_module() par le système d'importation déclenche maintenant un ImportWarning, car exec_module() est préféré ;
- sqlite3.OptimizedUnicode est non documenté et obsolète depuis Python 3.3. Il est maintenant déprécié, et sa suppression est prévue en Python 3.12 ;
- la fonction intégrée non documentée sqlite3.enable_shared_cache est maintenant obsolète, et sa suppression est prévue dans Python 3.12. Son utilisation est fortement déconseillée par la documentation de SQLite3 ;
- etc.
Suppressions
- suppression des méthodes spéciales __int__, __float__, __floordiv__, __mod__, __divmod__, __rfloordiv__, __rmod__ et __rdivmod__ de la classe complexe. Ils ont toujours soulevé un TypeError ;
- la méthode ParserBase.error() du module privé et non documenté _markupbase a été supprimée. html.parser.HTMLParser est la seule sous-classe de ParserBase et son implémentation error() a déjà été supprimée dans Python 3.5 ;
- suppression de l'attribut unicodedata.ucnhash_CAPI qui était un objet interne de PyCapsule. La structure privée _PyUnicode_Name_CAPI a été déplacée vers l'API C interne ;
- suppression du module d'analyseur, qui était obsolète dans la version 3.9 en raison du passage au nouvel analyseur PEG, ainsi que de tous les fichiers source et d'en-tête C qui n'étaient utilisés que par l'ancien analyseur, y compris node.h, parser.h, graminit.h et grammar.h ;
- suppression des fonctions PyParser_SimpleParseStringFlags(), PyParser_SimpleParseStringFlagsFilename(), PyParser_SimpleParseFileFlags() et PyNode_Compile() de l'API Public C qui étaient obsolètes dans la version 3.9 en raison du passage au nouvel analyseur PEG ;
- suppression du module de formatage qui est obsolète depuis Python 3.4. Il est quelque peu obsolète, peu utilisé et non testé. Il était initialement prévu de le supprimer dans Python 3.6, mais ces suppressions ont été reportées après la fin de vie de Python 2.7 ;
- etc.
Source : Python 3.10a6
Et vous ?
Que pensez-vous des nouvelles fonctionnalités de Python 3.10 ?
Voir aussi
Le conseil de direction de Python a accepté d'ajouter la correspondance de motifs au langage, notamment les PEP 634, 635 et 636
Intel® Parallel Studio ne sera plus disponible en 2021 et va laisser place à oneAPI, la prochaine génération d'outils de dev Intel® pour la création et le déploiement d'apps hautes performances
Python et C++ sont les langages qui ont connu la plus forte croissance de popularité sur l'année 2020, selon les statistiques de l'index TIOBE
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