Nouveautés de Python 3.9 (Résumé)

introduction

J'ai publié un article résumant le contenu des nouveautés de Python 3.5.

À partir de maintenant, le cycle de publication sera plus rapide, il semble donc que la fréquence de publication augmentera, mais je peux le faire en tant qu'ancien ingénieur boursier qui poursuit Python depuis 1.x Je veux juste continuer.

Et, comme je l'ai écrit dans cet article, Python2 a atteint la fin de vie le 1er janvier de cette année. J'ai hâte de voir quelles nouvelles fonctionnalités seront ajoutées à 3.9, qui sera publiée pour la première fois parmi les seuls Pythons qui ont Python 3 maintenu.

De plus, par rapport à la fois précédente, j'ai changé la façon de résumer par rapport à la fois précédente, par exemple "De petits changements sont écrits dans cet article, de grands changements sont écrits dans un autre article et un lien est fait ici", mais je voudrais également le suivre cette fois. Et au lieu de couvrir tous les changements, je me concentrerai sur ce qui m'intéresse personnellement.

Tout d'abord, la feuille de route de développement (PEP-596), qui est devenue un cycle d'un an à partir de ce moment.

Journal des modifications

2020.05.31

La première version bêta est sortie le 2020-05-19 presque comme prévu. Les nouvelles fonctionnalités de la version 3.9 sont maintenant terminées.

Ce qui suit a été ajouté aux "Modules nouvellement ajoutés".

Ce qui suit a été ajouté à "Amélioration du module".

2020.05.04

La version alpha finale, a6, est sortie le 2020-04-28. Il est encore environ une semaine de retard.

Ce qui suit a été ajouté aux «Nouvelles fonctionnalités d'intérêt».

Ce qui suit a été ajouté à "Amélioration du module".

2020.04.06

A4 est sorti le 2020-02-26 et a5 le 2020-03-23. C'est presque comme prévu avec un retard d'environ une semaine. Je pensais écrire de nouvelles fonctionnalités après la sortie de la version bêta, mais je l'ai mise à jour car elle était assez accumulée. Je ne les appellerai pas tous en même temps, alors je les ajouterai petit à petit.

2020.01.27

A3 est sorti le 2020-01-25. Pour autant que je sache, il ne semble pas y avoir de mise à jour majeure après le 1/18. Bogue GC (Garbage Collection)の修正が取り上げられていました。なおスケジュール的にa3は少し送れましたが、次のa4の予定は変わっていません。

2020.01.18

Première version. a2 est sorti le 2019-12-18, mais j'écris en fonction des nouveautés. Comme l'a3 était prévu pour le 2020-01-13, je pensais l'attendre, mais il semble qu'il soit tard, alors je vais le sortir pour le moment.

Faits saillants de la version

Vérifiez l'avertissement de dépréciation!

La période de support pour Python 2.7 a expiré et les anciennes fonctions compatibles qui ont été laissées seront coupées ou bientôt. Ils émettent des "DeprecatedWarning" depuis des années, mais il est possible qu'ils ne fonctionnent pas dès qu'ils sont mis à jour à moins qu'ils ne soient sérieusement vérifiés. Pour vérifier, vous pouvez soit émettre un message d'avertissement comme -W default au moment de l'exécution, soit sauter le pas et faire une erreur avec -W error.

Nouvelles fonctionnalités intéressantes

Vous pouvez utiliser l'opérateur d'ensemble de somme dans le type de dictionnaire

→ Article séparé: Nouvelles fonctionnalités de Python 3.9 (1) - L'opérateur d'ensemble de somme peut être utilisé dans le type dictionnaire

PEP 616 Ajout d'une méthode pour supprimer les préfixes et les suffixes des chaînes

Les méthodes «removeprefix (prefix)» et «removesuffix (suffix)» ont été ajoutées à «str», «bytes», «bytearray» et «collections.UserString». Il s'agit d'une méthode qui coupe les sous-chaînes au début et à la fin d'une chaîne (ou d'une chaîne d'octets). Par exemple

>>> 'test_sample.txt'.removeprefix('test_')
'sample.txt'
>>> 'abc.doc'.removesuffix('.doc')
'abc'

Vous pouvez faire quelque chose comme ça. Je me demande: "Hein? N'y avait-il pas une telle méthode?", Mais ce n'était pas le cas. En fait, il existe des méthodes similaires telles que «lstrip» et «rstrip». Normalement

>>> '   spacey_head'.lstrip()
'spacey_head'
>>> 'spacey_tail   '.rstrip()
'spacey_tail'

Il est utilisé pour effacer les caractères vides sous la forme de, mais quand un argument est donné à cela, il a une spécification étrange (?) Qui "supprime jusqu'à ce qu'il ne corresponde à aucun des caractères contenus dans la chaîne de caractères". Il est facile de faire des erreurs. Par exemple, essayez de faire la même chose que l'exemple ci-dessus

>>> 'abc.doc'.rstrip('.doc')
'ab'
>>> 'test_sample.txt'.lstrip('test_')
'ample.txt'

Ensuite, il disparaît dans un endroit inattendu et vous pourriez être surpris. En fait, ce comportement déroute les utilisateurs de Python, ce qui est l'une des raisons de l'ajout de nouvelles méthodes pour supprimer les préfixes et les suffixes.

PEP 585 Vous pourrez taper avec des types de collection standard

Dans le passé, lorsque vous vouliez taper-annoter un type de collection tel qu'une liste ou un taple, vous utilisiez le module typing List ou Tuple` pour ce faire.

import typing
def greet_all(names: typing.List[str]) -> None:
    for name in names:
        print("hello", name)

Beaucoup de gens aimeraient utiliser les noms de type «list» et «tuple» tels quels, tout comme «str» et «int ». Cela sera réalisé en 3.9. En d'autres termes

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

Vous pourrez écrire!

PEP 617 Présentation d'un nouvel analyseur

La partie qui lit et analyse le code dans le système de traitement du langage s'appelle un analyseur, mais jusqu'à présent, Python utilisait un type d'analyseur appelé LL (1). Il s'agit d'un analyseur qui effectue une analyse de syntaxe descendante avec une seule analyse prospective, et est souvent utilisé dans l'analyse du langage de programmation avec le type ascendant appelé type LR. Bien qu'une analyse efficace soit possible, il y a le problème que la grammaire qui peut être traitée est limitée. Il existe déjà une syntaxe que LL (1) ne peut pas gérer en Python, donc une logique spéciale est intégrée en tant que post-traitement de l'analyse parseur. Cette fois, nous allons introduire un nouvel analyseur PEG afin que l'analyseur seul puisse gérer différentes syntaxes.

Par exemple, si vous souhaitez lier plusieurs variables avec l'instruction with

with (
    open("a_really_long_foo") as foo,
    open("a_really_long_baz") as baz,
    open("a_really_long_bar") as bar
):
    ...

Je veux l'écrire comme ça, mais cela ne peut pas être géré par l'analyseur actuel. Je veux introduire un nouvel analyseur pour gérer ce genre de chose.

Python 3.9 possède également un analyseur LL (1) traditionnel. La valeur par défaut utilise le nouvel analyseur, mais vous pouvez également appeler l'ancien avec l'option d'invocation (-X oldparser) ou la variable d'environnement ( PYTHONOLDPARSER = 1). Cependant, il s'agit d'une mesure transitoire, et en ce qui concerne Python 3.10, l'ancien analyseur sera retiré et seulement le nouveau. Et les spécifications linguistiques sont basées sur cela.

Autres changements de langue

L'erreur d'importation déclenche désormais ʻImportError au lieu de ValueError`

Dans un package qui a une structure hiérarchique, les modules de la hiérarchie supérieure

import ..module_1

Vous pouvez l'importer comme ceci, mais si vous faites cela au niveau supérieur du package, par exemple, vous obtiendrez une erreur. Dans ce cas, jusqu'à maintenant

ValueError: attempted relative import beyond top-level package

J'ai eu une erreur de valeur, mais à partir de 3,9

ImportError: attempted relative import beyond top-level package

Cela devient «Erreur d'importation». De même, l'erreur dans ʻimportlib.util.resove_name () va de ValueError à ʻImportError. C'est un changement incompatible, donc le code qui intercepte et gère cette exception doit être changé, mais c'est un changement légitime.

Le chemin d'exécution lors de l'exécution d'un fichier local devient un chemin absolu

Lorsque vous utilisez python script.py, le nom de fichier du script exécuté sera entré dans l'attribut __file__. Je vais. ~~ De plus, Quoi de neuf dit que la valeur de sys.path [0] est aussi un chemin absolu, mais c'est aussi le cas avec la version actuelle, donc je pense que c'est une erreur dans le document. Je suis en train de penser. ~~ -> Ceci a été corrigé en listant un rapport de bogue.

Ensuite, suite aux discussions du passé, il semble que sys.argv [0] essayait également de changer en chemin absolu. Cependant, il y avait un tsukkomi disant que la gamme d'influence était trop large et il semble qu'elle a été annulée. Je suis content de penser que c'est un peu exagéré. Huh.

Changements dans le comportement de replace pour les chaînes vides (" ")

Le comportement lors de l'application de la méthode replace à une chaîne de caractères vide (" ") change. Auparavant, l'argument optionnel count (qui spécifie le nombre de changements à appliquer) donnait des résultats étranges.

"".replace("", "p") = "p"
"".replace("", "p", 1) = ""
"".replace("", "p", 2) = ""

Lorsqu'il atteint 3,9, il devient plus cohérent.

"".replace("", "p") = "p"
"".replace("", "p", 1) = "p"
"".replace("", "p", 2) = "p"

Eh bien, pour être clair, je pense que c'est un niveau de correction de bogue, mais "(je ne pense pas que ce soit possible) je ne veux pas revenir en arrière vers la version précédente car ce serait un problème pour les personnes qui implémentent ce comportement." chose.

Module nouvellement ajouté

zoneinfo

Un nouveau module zone info a été ajouté à la bibliothèque standard. Il fournit les fonctionnalités de la base de données de fuseaux horaires de l'IANA en standard. Certaines des fonctions fournies par le module datetime prennent les informations de fuseau horaire comme argument, mais la classe standard timezone fournit des fonctionnalités minimales et essaie de faire quelque chose d'un peu élaboré. Ensuite, j'ai dû me fier à une bibliothèque externe telle que python-dateutil. C'est beaucoup plus facile avec le nouveau module zoneinfo ajouté en 3.9.

Par exemple.

>>> from zoneinfo import ZoneInfo
>>> from datetime import datetime

>>> tzinfo = ZoneInfo("Europe/Brussels")
>>> dt = datetime(2020, 10, 24, 12, tzinfo=tzinfo)
>>> print(dt)
2020-10-24 12:00:00+02:00
>>> dt.tzname()
'CEST'

>>> dt = datetime(2020, 10, 25, 12, tzinfo=tzinfo)
>>> print(dt)
2020-10-25 12:00:00+01:00
>>> dt.tzname()
'CET'

De nombreux pays d'Europe occidentale ont adopté «l'heure d'Europe centrale». Les pays de ce fuseau horaire ont l'heure d'été du dernier dimanche de mars au dernier dimanche d'octobre, mais si vous utilisez zoneinfo, il n'y a pas de problème à partir des informations de localisation uniquement sans connaître le moment de commutation. Vous pouvez voir qu'il peut gérer les fuseaux horaires.

Améliorations du module

asyncio

Il y a quelques changements dans ʻasyncio`.

Ce que j'ai trouvé le plus intéressant, c'est l'ajout de PidfdChildWatcher. Il est possible de créer plusieurs processus enfants dans ʻasyncio` et d'attendre le résultat de manière asynchrone, mais il est étonnamment difficile de "détecter la fin du processus enfant". Jusqu'à présent, environ 4 méthodes ont été implémentées, une méthode est de créer un thread pour surveiller chaque fois qu'un processus enfant est créé, deux méthodes utilisent un signal (SIGCHLD) et ʻos.waitpid () ʻest utilisé. Il y avait un moyen. Chacun a ses avantages et ses inconvénients et peut être modifié par l'utilisateur selon les besoins (la valeur par défaut est threadée). Cette fois, celui qui utilise pidfs est ajouté ici.

C'est la première fois que j'apprends les pidfs, mais avec un nouveau périphérique introduit sous Linux, il sera possible de pointer des processus avec des descripteurs de fichiers. Sous Unix, les processus sont généralement pointés par PID (ID de processus), mais comme ils sont partagés dans tout le système et sont des entiers signés 32 bits, ils finiront par être épuisés si le système continue de s'exécuter et que les processus sont créés et supprimés à plusieurs reprises. Je le ferai. Cela se traduit par la réutilisation des PID précédemment utilisés (des processus qui ont déjà disparu), qui, nous le savons, peuvent être une faille de sécurité. En guise de contre-mesure, l'idée d'un descripteur de fichier qui attribue un numéro individuel à chaque processus est appliquée au processus et l'accès au processus enfant peut être effectué en l'utilisant.

Le PidfdChildWatcher ajouté dans 3.9 ne nécessite pas de threads ou de signaux et n'interfère pas avec d'autres processus, ce qui en fait une implémentation de surveillance de processus enfant" juste ". Le problème est qu'il ne peut être utilisé qu'avec des versions relativement nouvelles de Linux (5.3 et plus), mais je pense que s'il se propage progressivement, il y aura plus d'opportunités de l'utiliser.

datetime

datetime.isocalendar () et date.isocalendar () utilisé pour renvoyer le nplet(année, semaine, jour de la semaine)comme suit:

>>> from datetime import datetime
>>> dt = datetime(2020,5,30)
>>> isocal = dt.isocalendar()
>>> isocal
(2020, 22, 6)
>>> isocal[0]
2020

Avec les tapples, c'est difficile à comprendre car il faut utiliser un index numérique pour accéder aux informations qu'il contient. Cela renverra les taples nommés de 3.9.

>>> from datetime import datetime
>>> dt = datetime(2020,5,30)
>>> isocal = dt.isocalendar()
>>> isocal
datetime.IsoCalendarDate(year=2020, week=22, weekday=6)
>>> isocal.year
2020

C'est beaucoup plus facile car vous pouvez y accéder comme un attribut d'objet.

functools

Une fonction de tri des graphes dirigés appelée TopologicalSorter a été fournie en tant que classe. Cela a été traité dans un article séparé dans Quoi de neuf en Python 3.9 (2) - Tri des graphes non-circuit dirigés en Python.

hashlib

En tant qu'option lors de la compilation des systèmes de traitement Python, il est désormais possible de désactiver (sélectivement) l'implémentation de la fonction de hachage intégrée. Il sert à imposer l'utilisation de l'implémentation OpenSSL.

ipaddress

L'adresse de portée définie dans la RFC4007 peut être spécifiée sous la forme «<ipv6_address>% scope_id». De plus, un attribut appelé scope_id a été ajouté à la classe ʻIPv6Address`, et vous pouvez y vérifier la valeur des adresses étendues.

math

Gcd, qui calcule l'engagement maximum, peut désormais prendre 3 arguments ou plus. Auparavant, il était limité à deux. De plus, «lcm» a été ajouté pour calculer le multiple commun minimum. Cela prend en charge 3 arguments ou plus depuis le début.

>>> import math
>>> math.gcd(120, 156, 180)
12
>>> math.lcm(120, 156, 180)
4680

os

pidfd_open () et P_PIDFD ont été ajoutés. Cela fait partie du support des pidfs dont nous avons parlé dans ʻasyncio` ci-dessus.

pathlib

Pathlib.Path.readlink () a été ajouté pour suivre le lien symbolique. Par exemple, si vous avez un lien appelé b-> a, vous pouvez toujours utiliser ʻos.readlink ()`

>>> import os
>>> os.readlink('b')
'a'

Mais j'ai dû donner le chemin du fichier sous forme de chaîne. Depuis 3.9, readlink () a été ajouté en tant que méthode à l'objet Path, donc

>>> from pathlib import Path
>>> p = Path('b')
>>> p.readlink()
PosixPath('a')

Vous pouvez le faire comme ça. Dans cet exemple, il y a plus d'étapes que ʻos.readlink () , mais un outil qui utilise un objet Path pour afficher des liens symboliques sous / usr / local / bin`, par exemple, ressemble à ceci Peut écrire.

from pathlib import Path

p = Path('/usr/local/bin/')
for child in p.iterdir():
  if child.is_symlink():
    print(f'{child} -> {child.readlink()}')

random

Ajout de Random.randbytes (), qui renvoie des nombres aléatoires en octets de longueur arbitraire. Cependant, comme le nombre aléatoire généré par le module aléatoire est un nombre pseudo aléatoire, il est bon pour la modélisation et la simulation, mais il n'est pas recommandé pour les applications de sécurité et le chiffrement. Une fonction appelée secrets.token_bytes () est déjà fournie à ces fins.

typing

Une classe appelée ʻAnnotated a été ajoutée au module typing` pour vous permettre d'ajouter des métadonnées pour taper des informations d'indication.

Par exemple, supposons qu'une variable membre appelée value dans une classe appelée ʻIntInRange soit de type integer (ʻint) et a une valeur comprise entre -10 et 5. Dans le passé, des informations de type indiquant qu'il s'agissait d'un type entier étaient ajoutées, mais il n'était pas possible de spécifier une plage de nombres. À partir de 3.9, vous pouvez mettre des données arbitraires dans le deuxième argument et les suivants de ʻAnnotated` comme indiqué ci-dessous, j'ai donc essayé de spécifier la plage de valeurs numériques avec un taple.

Et les informations d'indication peuvent être récupérées en passant True à l'argument ʻinclude_extras ajouté de 3.9 à la fonction get_type_hints`. Si vous créez un vérificateur de type spécial à l'aide de cela, vous pouvez vérifier le type, y compris la plage de valeurs.

from typing import Annotated, get_type_hints

class IntInRange:
    value: Annotated[int, (-10, 5)]

get_type_hints(IntInRange) ==  {'value': int}
get_type_hints(IntInRange, include_extras=True) == {'value': Annotated[int, (-10, 5)]}

optimisation

Prévu pour être aboli

Fonction supprimée

Résumé

Voici un résumé des modifications apportées à Python 3.9. Puisque la version 3.9 est également en version bêta, je pense que cet article est presque complet, mais il y a des parties d'optimisation et des parties qui n'ont pas encore été écrites, je les ajouterai donc si nécessaire.

Recommended Posts

Nouveautés de Python 3.10 (Résumé)
Nouveautés de Python 3.9 (Résumé)
Quoi de neuf dans Python 3.5
Quoi de neuf dans Python 3.6
Nouveau dans Python 3.4.0 (2) --enum
Nouveau dans les dictionnaires de fusion python3.9
Nouveau dans Python 3.4.0 (1) --pathlib
Résumé de la détection de visage en Python
Résumé Python
Résumé Python
Quadtree en Python --2
Python en optimisation
Nouveautés de Python 3.9 (2) - Tri des graphes non circulés dirigés en Python
Métaprogrammation avec Python
Python 3.3 avec Anaconda
Géocodage en python
SendKeys en Python
Nouveau dans Django 1.8 Expressions conditionnelles #djangoja
Méta-analyse en Python
Unittest en Python
Résumé du didacticiel Python
Époque en Python
Discord en Python
Allemand en Python
nCr en python
N-Gram en Python
Programmation avec Python
Plink en Python
Nouvelles fonctionnalités de Python 3.4.0 (3) - Fonctions génériques à distribution unique
FizzBuzz en Python
Sqlite en Python
Résumé des méthodes intégrées, etc. de la liste Python
LINE-Bot [0] en Python
CSV en Python
Assemblage inversé avec Python
résumé relatif à python
Constante en Python
nCr en Python.
format en python
Scons en Python 3
Puyopuyo en python
python dans virtualenv
PPAP en Python
Quoi de neuf dans datetime qui est un peu plus utile dans Python 3
Quad-tree en Python
Réflexion en Python
Chimie avec Python
Hashable en Python
DirectLiNGAM en Python
LiNGAM en Python
Aplatir en Python
Résumé des bases de Python
Aplatir en python
Résumé de l'utilisation de MNIST avec Python
Créer une nouvelle page en confluence avec Python
Résumé des opérations Excel utilisant OpenPyXL en Python
Liste triée en Python
AtCoder # 36 quotidien avec Python