URL: https://linuxfr.org/news/sortie-de-python-3-7 Title: Sortie de Python 3.7 Authors: Collectif Davy Defaud, Philippe F, cracky, Nairwolf, BAud, M5oul, dovik, bubarđŸŠ„, JulienPalard, BenoĂźt Sibaud, Nairwolf, Xavier Teyssier, Nils Ratusznik, mats, audionuma, Xavier Combelle et esdeem Date: 2018ćčŽ07月12æ—„T21:21:02+02:00 License: CC By-SA Tags: python, python3, sortie_version et flatpak Score: 74 Python 3.7 a Ă©tĂ© publiĂ© le 27 juin 2018, soit un an et demi aprĂšs la prĂ©cĂ©dente version. Celle‐ci vient avec son lot de nouveaux modules et fonctionnalitĂ©s que nous dĂ©taillons dans la suite de la dĂ©pĂȘche. ![Logo de Python](https://upload.wikimedia.org/wikipedia/commons/f/f8/Python_logo_and_wordmark.svg) ---- [Python 3.7](https://www.python.org/downloads/release/python-370/) [What’s New in Python 3.7](https://docs.python.org/3/whatsnew/3.7.html) [Cool New Features in Python 3.7](https://realpython.com/python37-new-features/) [Python 3.7 sort de sa coquille](http://sametmax.com/python-3-7-sort-de-sa-coquille/) ---- # Python 3.7 en rĂ©sumĂ© La fonctionnalitĂ© la plus « marquante » est sans doute l’introduction du module [dataclasses](https://docs.python.org/3/library/dataclasses.html) qui permettra aux dĂ©veloppeurs d’écrire des classes avec une syntaxe bien plus concise qu’à l’accoutumĂ©e. Une nouvelle fonction native a Ă©tĂ© introduite, Ă  savoir [`breakpoint()`](https://docs.python.org/3/library/functions.html#breakpoint), facilitant l’utilisation du dĂ©bogueur et offrant la possibilitĂ©, pour des usages plus avancĂ©s, de le personnaliser. Le module `asyncio` a Ă©tĂ© fortement amĂ©liorĂ©, notamment en simplifiant l’API ; en plus de cela, `async` et `await` deviennent dĂ©sormais des mots clefs. Ajoutons Ă  cela, le fait que la conservation de l’ordre d’insertion des `dict` est dĂ©sormais officielle d’aprĂšs les spĂ©cifications, et vous aurez une bonne vision des modifications liĂ©es Ă  la syntaxe du langage. Python 3.7 apporte aussi des amĂ©liorations sur des fonctionnalitĂ©s plus avancĂ©es, comme la possibilitĂ© de [personnaliser l’accĂšs aux attributs de module](https://www.python.org/dev/peps/pep-0562/), mais aussi l’introduction du module `typing` dans le cƓur de Python, ainsi que la possibilitĂ© d’effectuer une [Ă©valuation diffĂ©rĂ©e des annotations](https://www.python.org/dev/peps/pep-0563/), ce qui amĂšne Ă  Python des Ă©volutions intĂ©ressantes concernant son systĂšme de typage. Enfin, cette version vient avec la possibilitĂ© de faire des [_builds_ reproductibles](https://www.python.org/dev/peps/pep-0552/), et de trĂšs nombreuses [amĂ©liorations de performance](https://docs.python.org/3.7/whatsnew/3.7.html#whatsnew37-perf) faisant de Python 3.7 la version la plus rapide de Python. # Nouveaux modules ## PEP 557 : Dataclasses La [PEP 557](https://www.python.org/dev/peps/pep-0557/) introduit le nouveau module [_dataclasses_](https://docs.python.org/3/library/dataclasses.html#) qui fournit le dĂ©corateur `@dataclass` permettant d’écrire une « classe de donnĂ©es » de façon plus concise. Les _dataclasses_ peuvent ĂȘtre vues comme un _named tuple_ mutable avec des valeurs par dĂ©faut. Le dĂ©corateur de classe repose sur la [PEP 526](https://www.python.org/dev/peps/pep-0526/) qui a introduit les annotations de variables. On peut donc dĂ©sormais Ă©crire ceci en Python 3.7 : ```python from dataclasses import dataclass @dataclass class BankAccount: """class that corresponds to a bank account.""" bank_name: str # no default value owner_name: str currency: str = "dollar" # assign a default value for 'currency' value: int = 0 def tax(self, val) -> int: self.value -= val ``` Cela donne ensuite : ```python>>> print(BankAccount('BNP', 'toto')) BankAccount(bank_name='BNP', owner_name='toto', currency='dollar', value=0)>>> account = BankAccount('LCL', 'tata', 'euros', 1000)>>> account.tax(5)>>> print(account.value) 995 ``` L’intĂ©rĂȘt d’utiliser une _dataclass_ et non pas un _namedtuple_, c’est qu’il s’agit ni plus ni moins d’une classe normale en Python. On peut donc utiliser tous les concepts de la programmation objet associĂ©s aux classes (hĂ©ritage, mĂ©taclasse, _doc strings_). On voit dans l’exemple ci‐dessus que le dĂ©corateur va gĂ©nĂ©rer une classe et va fournir automatiquement le `__init__`, le `__repr__`, ainsi que la fonction d’égalitĂ© `__eq__` : ```python3>>> print(account) >>> dir(account1) ['__annotations__', '__class__', '__dataclass_fields__', '__dataclass_params__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bank_name', 'currency', 'owner_name', 'tax', 'value'] ``` Il est possible de passer des paramĂštres au dĂ©corateur pour gĂ©nĂ©rer, par exemple, des fonctions de comparaison avec le paramĂštre `order`. Par exemple, la classe suivante permettra de faire des comparaisons : ```python @dataclass(order=True) class Item: price: float product_name: str >>> pomme = Item(1.5, 'pomme')>>> ordinateur = Item(500, 'ordinateur')>>> pomme < ordinateur True ``` Python va comparer les Ă©lĂ©ments en considĂ©rant que les Ă©lĂ©ments sont des _tuples_, il va donc comparer les champs un par un. Il est possible de convertir une instance _dataclass_ en _tuple_ ou _dict_ via les fonctions `astuple()` ou `asdict()` disponibles dans le module. Dans l’exemple ci‐dessus, cela donne : ```python from dataclasses import astuple, asdict>>> print(astuple(pomme)) (1.5, 'pomme')>>> print(asdict(pomme)) {'price': 1.5, 'product_name': 'pomme'} ``` Les _dataclasses_ peuvent faire penser Ă  l’utilisation que l’on peut faire des _named tuples_, mais ces derniers ont certaines restrictions. De par leur nature, ce sont des objets immuables. Ainsi, si l’on Ă©crit : ```python from collections import namedtuple Item = namedtuple('Item', ['price', 'product_name']) apple = Item(2, 'apple') ``` Modifier le champ `price` va provoquer une erreur : ```python>>> apple.price = 3 AttributeError: can't set attribute ``` De mĂȘme, on peut accidentellement comparer deux _named tuples_ qui ont les mĂȘmes valeurs, mais qui ne reprĂ©sentent pas les mĂȘmes objets : ```python Stock = namedtuple('Stock', ['quantity', 'name']) apple_stock = Stock(2, 'apple')>>> apple_stock == apple True ```` L’utilisation de _dataclass_ empĂȘche cela car la comparaison de deux objets de classes diffĂ©rentes renverra toujours `False`. ## PEP 567 : Variables contextualisĂ©es Cette nouvelle fonctionnalitĂ© demande une petite introduction. Si l’on prend un programme « classique » _mono‐thread_ avec une exĂ©cution linĂ©aire, toutes les variables sont accessibles simplement en lecture ou Ă©criture et ne sont pas susceptibles de changer. Jusque‐lĂ , rien de compliquĂ©. Maintenant, prenons le cas d’un programme _multi‐thread_. Le contexte d’exĂ©cution — et en particulier toutes les variables — est partagĂ© entre tous les _threads_. Il est donc difficile pour un _thread_ de manipuler des donnĂ©es privĂ©es, rĂ©servĂ©es au _thread_. Python propose une solution pour ce problĂšme avec [l’API _threading.local_](https://docs.python.org/3/library/threading.html?highlight=thread%20local#thread-local-data), qui fournit un objet oĂč la modification et la rĂ©cupĂ©ration d’une variable donnĂ©e pourra ĂȘtre diffĂ©rente suivant le _thread_ qui l’appelle. Avec l’arrivĂ©e de l’asynchronicitĂ© dans l’exĂ©cution du code, de nouveaux problĂšmes se prĂ©sentent : on peut avoir Ă  l’intĂ©rieur du mĂȘme _thread_ d’exĂ©cution plusieurs fonctions qui s’exĂ©cutent de façon asynchrone et qui auraient besoin d’un contexte diffĂ©rent par fonction plutĂŽt que par _thread_. C’est ce problĂšme que rĂ©sout le nouveau module `contextvars`. Son introduction a Ă©tĂ© discutĂ©e et approuvĂ©e via la [PEP 567 — Variables contextualisĂ©es](https://www.python.org/dev/peps/pep-0567/). Cette PEP est elle‐mĂȘme un sous‐ensemble d’une PEP plus ambitieuse, la [PEP 550 — Contexte d’exĂ©cution](https://www.python.org/dev/peps/pep-0550/). Cette derniĂšre apportait la notion de contexte Ă  un ensemble plus large de construction Python (en particulier les gĂ©nĂ©rateurs) mais n’a pas fait l’unanimitĂ© parmi les _core‐developers_. L’auteur de la PEP, Yury Selivanov, a repris les parties qui faisaient consensus dans la PEP 567, qui a Ă©tĂ© intĂ©grĂ©e dans Python 3.7. L’exemple suivant utilise _asyncio_ et une liste pour crĂ©er trois contextes diffĂ©rents dans `init_var()`, puis le programme appelle la fonction `hello()`, Ă  chaque fois avec une valeur diffĂ©rente de _name_ programmĂ©e dans le contexte : ```python import contextvars import asyncio import datetime all_names = ['Donald', 'Mickey', 'Dominique'] # La variable contextuelle name = contextvars.ContextVar('name') def hello(): date = datetime.datetime.now().strftime('%H:%M:%S') print('Bonjour {}, il est {}'.format(name.get(), date)) def init_var(event_loop): name.set(all_names.pop()) event_loop.call_later(1, hello) # on rĂ©cupĂšre une boucle d’évĂšnements event_loop = asyncio.get_event_loop() # on planifie des appels toutes les secondes event_loop.call_later(0, init_var, event_loop) event_loop.call_later(1, init_var, event_loop) event_loop.call_later(2, init_var, event_loop) # on prĂ©voit de s’arrĂȘter tout de mĂȘme event_loop.call_later(5, event_loop.stop) # on met tout en route et on attend event_loop.run_forever() ``` Le rĂ©sultat : >py -3.7 asyncio_example2.py Bonjour Dominique, il est 13:10:03 Bonjour Mickey, il est 13:10:04 Bonjour Donald, il est 13:10:05 ## Ajout de l’API « importlib.resources » pour lire des ressources embarquĂ©es Le terme « ressource » dĂ©signe ici un fichier de donnĂ©es. Avec cette nouvelle API, il est possible d’accĂ©der en lecture Ă  un fichier qui serait embarquĂ© dans un paquet Python, et donc installĂ© en mĂȘme temps que le paquet. Ou bien de donner un accĂšs en lecture Ă  une donnĂ©e qui fait partie de l’application distribuĂ©e mais n’est pas reprĂ©sentĂ©e strictement comme un fichier. AccĂ©der Ă  des ressources de donnĂ©es est un besoin courant pour certains types d’applications. Par exemple, les applications graphiques peuvent ainsi distribuer aisĂ©ment leurs icĂŽnes et images. Avant la disponibilitĂ© de cette API, embarquer un fichier de donnĂ©es Ă  l’empaquetage et y accĂ©der Ă  l’exĂ©cution se faisait soit Ă  coups de bidouilles sur la variable `__file__` pour localiser le module en cours et en dĂ©duire l’emplacement du fichier (la mĂ©thode _old school_, qui ne marchait pas toujours dans des environnements complexes), soit en utilisant [l’API _Basic Resource Access_ de _setuptools_](https://setuptools.readthedocs.io/en/latest/pkg_resources.html#basic-resource-access), l’outil d’empaquetage de Python. C’est surtout ce dernier qui est remplacĂ© par la nouvelle API, plus robuste et plus simple Ă  utiliser. Une [documentation spĂ©cifique](http://importlib-resources.readthedocs.io/en/latest/migration.html) est disponible pour migrer de _pkg_resources_ Ă  _importlib.resources_, en plus de la [documentation standard](https://docs.python.org/3/library/importlib.html#module-importlib.resources). À noter la disponibilitĂ© d’un portage vers les prĂ©cĂ©dentes versions de Python (2.7, 3.4, 3.5 et 3.6) [via le paquet _importlib_resources_ sur PyPi](https://pypi.org/project/importlib_resources/). C’est d’ailleurs dans ce paquet que l’API a maturĂ© dans les six derniers mois avant de rejoindre Python 3.7. # Syntaxe et caractĂ©ristiques des dictionnaires ## `async` et `await` deviennent des mots clefs rĂ©servĂ©s Pour Ă©viter les problĂšmes de rĂ©tro‐compatibilitĂ©, `async` et `await` n’ont pas Ă©tĂ© ajoutĂ©s Ă  la liste des mots clefs rĂ©servĂ©s lorsqu’ils ont Ă©tĂ© inclus dans Python 3.5. Il Ă©tait donc possible de nommer des variables et des fonctions _async_ ou _await_. DorĂ©navant, ce n’est plus possible en Python 3.7 : ```python>>> async = 42 File "", line 1 async = 42 ^ SyntaxError: invalid syntax ``` ```python>>> def await(): File "", line 1 def await(): ^ SyntaxError: invalid syntax ``` ## Ordre d’insertion dans les dictionnaires La conservation de l’ordre d’insertion dans les _dict_ est dĂ©sormais [officielle](https://mail.python.org/pipermail/python-dev/2017-December/151283.html). Ce comportement provient au dĂ©part d’un effet de bord de [l’amĂ©lioration de l’implĂ©mentation des dictionnaires](https://docs.python.org/3.6/whatsnew/3.6.html#new-dict-implementation) (consommation mĂ©moire rĂ©duite de 20 Ă  25 %) rĂ©alisĂ©e pour la version 3.6. Cette propriĂ©tĂ© a Ă©tĂ© dans un premier temps dĂ©finie en tant que dĂ©tail d’implĂ©mentation de CPython 3.6, afin de ne pas trop perturber la compatibilitĂ© arriĂšre et les autres implĂ©mentations de Python. ConcrĂštement, en Python 3.5 : ```python>>> d = {}>>> d['a'] = 1>>> d['z'] = 2>>> for k in d: print(k) # affiche toutes les clefs du dictionnaire z a ``` L’ordre de parcours des clefs du dictionnaire est non dĂ©fini Ă  l’avance, et peut bouger au fur Ă  mesure que le dictionnaire Ă©volue : ```python>>> d['j'] = 3>>> for k in d: print(k) # affiche toutes les cles du dictionnaire z j a ``` Le nouvel Ă©lĂ©ment ajoutĂ© a changĂ© l’ordre de parcours. Maintenant, en Python 3.6 et 3.7 : ```python>>> d={}>>> d['a'] = 1>>> d['z'] = 2>>> for k in d: print(k) a z>>> d['j'] = 3>>> for k in d: print(k) a z j ``` Les clefs sont maintenant affichĂ©es dans l’ordre oĂč elles ont Ă©tĂ© ajoutĂ©es au dictionnaire. Un effet de bord sympa est que pour les fonctions Ă  arguments par mot clef, l’ordre est prĂ©servĂ© aussi. L’ancien comportement en Python 3.5 : ```python>>> def f(**kw): ... for k in kw: print(k)>>> f(a=1, j=2, z=3) z j a>>> f(z=3, a=2, j=1) z j a ``` On constate que l’ordre d’affichage des clefs est celui du dictionnaire utilisĂ©, et va donc varier en fonction des clefs du dictionnaire. Maintenant, en Python 3.6 et 3.7 : ```python>>> f(a=1, j=2, z=3) a j z>>> f(z=3, j=2, a=1) z j a ``` L’ordre d’affichage dĂ©pend dĂ©sormais de l’ordre de crĂ©ation des clefs. Ce n’est pas une _killer‐feature_ de Python, mais c’est plutĂŽt confortable. _**Note personnelle de l’un des auteurs :** Ça m’est arrivĂ© plusieurs fois lors de phases de dĂ©bogage d’ĂȘtre perturbĂ© parce que les nouvelles entrĂ©es dans un dictionnaire Ă©taient affichĂ©es au milieu plutĂŽt qu’à la fin. Ce ne sera plus le cas._ À noter que la classe [_OrderedDict_](https://docs.python.org/3/library/collections.html#ordereddict-objects) du module _collections_ devient beaucoup moins utile, mais pas nĂ©cessairement obsolĂšte : son auteur [Raymond Hettinger explique dans un courriel](https://mail.python.org/pipermail/python-dev/2017-December/151266.html) que l’implĂ©mentation de _OrderedDict_ est optimisĂ©e afin de permettre des ré‐ordonnancements rapides et frĂ©quents lors de l’évolution du dictionnaire. Ce n’est pas le cas des _dict_ normaux qui, eux, sont optimisĂ©s pour ĂȘtre compacts en mĂ©moire et rapides lors des accĂšs. Une autre diffĂ©rence est que pour ĂȘtre Ă©gaux, deux _dict_ normaux ont besoin d’avoir les mĂȘmes clefs et valeurs, alors que deux _OrderedDict_ ajoutent la contrainte que les clefs ont Ă©tĂ© insĂ©rĂ©es dans le mĂȘme ordre. # AmĂ©liorations ## PEP 553 : Introduction de la fonction breakpoint La [PEP 553](https://www.python.org/dev/peps/pep-0553/) introduit la nouvelle fonction native `breakpoint()` pour faciliter et uniformiser l’accĂšs au dĂ©bogueur Python. Auparavant, pour faire appel Ă  `pdb`, le dĂ©bogueur standard de Python, vous deviez Ă©crire `import pdb; pdb.set_trace()`. DĂ©sormais, vous pourrez faire `breakpoint()` uniquement. Cela a pour premier avantage de rĂ©duire le nombre de caractĂšres Ă  taper, et que ce soit plus facile Ă  retenir ; mais le vĂ©ritable avantage est la possibilitĂ© de personnaliser le comportement du dĂ©bogueur. En effet, cette nouvelle fonction native fait appel Ă  la fonction ```sys.breakpointhook()``` qui, elle‐mĂȘme, interroge une nouvelle variable d’environnement nommĂ©e ```PYTHONBREAKPOINT```. Selon la valeur choisie, on peut dĂ©sactiver le dĂ©bogage (pour le dĂ©sactiver dans un environnement de production), utiliser le comportement par dĂ©faut avec l’appel Ă  `pdb`, ou appeler un autre dĂ©bogueur (celui intĂ©grĂ© dans l’[EDI](https://fr.wikipedia.org/wiki/Environnement_de_d%C3%A9veloppement) utilisĂ©, par exemple). ## PEP 560 et PEP 563 : AmĂ©liorations autour des annotations Les annotations des paramĂštres et des valeurs de retour de fonctions ont Ă©tĂ© introduites en mĂȘme temps que le passage Ă  Python 3.0, par la PEP 3107 en 2006. À l’époque, la syntaxe a Ă©tĂ© choisie de façon « neutre » afin de ne pas forcer un fonctionnement spĂ©cifique alors que l’annotation de type Ă©tait encore quelque chose de trĂšs expĂ©rimental (voire d’inexistant) et novateur. Guido avait bien en tĂȘte que cela Ă©voluerait vers de l’annotation de type poussĂ©e (_cf._ son [blog](https://www.artima.com/weblogs/viewpost.jsp?thread=85551)), mais il Ă©tait trop tĂŽt pour figer cela dans le marbre et, surtout, le passage Ă  Python 3 occupait dĂ©jĂ  beaucoup de monde. Par neutre, on entend que l’on pouvait rajouter des trucs (techniquement des expressions) aprĂšs les arguments et les valeurs de retour des fonctions, mais que ces trucs Ă©taient totalement ignorĂ©s par l’implĂ©mentation, en dehors du fait qu’ils soient accessibles. Les annotations Ă©taient dĂ©crites dans la grammaire en tant que : ```python def foo(a: expression, b: expression = 5, *args: expression, **args: expression) -> expression: ... ``` Les deux exemples d’utilisation potentielle donnĂ©s dans la PEP Ă©taient : ```python def compile(source: "something compilable", filename: "where the compilable thing comes from", mode: "is this a single statement or a suite?"): ... def haul(item: Haulable, *vargs: PackAnimal) -> Distance: ... ``` Évidemment, c’était surtout le cas `haul()` qui motivait l’évolution. L’aspect « neutre » signifiait qu’en dehors de la syntaxe du langage et d’une fonction pour rapatrier la chaĂźne de l’annotation, on ne touche pas au fonctionnement interne du langage. Avançons de huit annĂ©es, jusqu’en 2014. Durant ces huit ans, des outils se sont emparĂ©s des possibilitĂ©s ouvertes par l’annotation de type et ont ainsi permis de vĂ©rifier statiquement la cohĂ©rence des types d’un ensemble de modules Python. Le plus connu alors est [_mypy_](https://github.com/python/mypy), dĂ©veloppĂ© par l’équipe de Dropbox, dans laquelle travaille Guido. Lorsqu’on l’exĂ©cute sur un ensemble de code Python, il fournit un rapport sur la cohĂ©rence globale des types dĂ©clarĂ©s dans les fonctions et leur utilisation (de la mĂȘme façon que les compilateurs C++, Java, etc.). En 2014, Guido propose une nouvelle PEP, la [PEP 484](https://www.python.org/dev/peps/pep-0484/) — _Indication de types_, pour standardiser la façon dont on dĂ©crit le type d’un paramĂštre dans les annotations. Le but est de permettre aux diffĂ©rents outils travaillant avec les annotations de type d’utiliser un vocabulaire commun. Cette PEP ajoute un module `typing` Ă  Python 3.5, qui permet de dĂ©finir des types complexes Ă  utiliser lors de l’annotation de type. Le module est provisionnel, ce qui veut dire qu’il est proposĂ© en l’état, mais qu’il pourrait encore Ă©voluer. ConcrĂštement, on peut maintenant Ă©crire : ```python def adder(val: int, l: Sequence[int]) -> List[int]: ret = [] for v in l: ret.append( v+val ) return ret ``` L’annotation `val: int` Ă©tait dĂ©jĂ  possible avant. La nouveautĂ© de la PEP 484 concerne tous les types Ă©laborĂ©s comme _Sequence_, _List_, _Dict_ et _Any_, ainsi que toutes les constructions pour fabriquer des types plus spĂ©cifiques ou plus gĂ©nĂ©riques. Le code ci‐dessus nĂ©cessite d’ĂȘtre prĂ©fixĂ© par la ligne suivante : ```python from typing import Sequence, List ``` En effet, les annotations sont des expressions ordinaires qui respectent la syntaxe Python. On note aussi la syntaxe inhabituelle, ` [ ]`. Il fallait une syntaxe lisible (pour rester dans l’esprit du langage) mais distincte de ce qui existe dĂ©jĂ , et qui ne crĂ©e pas de confusion pour l’interprĂ©teur Python. Il y a eu pas mal de dĂ©bat pour arriver Ă  ce choix. Cette syntaxe est possible grĂące Ă  l’utilisation d’une mĂ©thode `__getitem__()` dans la mĂ©ta‐classe . Si vous ne savez pas ce qu’est une mĂ©ta‐classe, ne vous en faite pas, c’est trĂšs trĂšs spĂ©cifique. En gros, une mĂ©ta‐classe fonctionne pour une classe de la mĂȘme façon qu’une classe pour une instance : elle permet de contrĂŽler la crĂ©ation de la classe et de lui adjoindre des mĂ©thodes gĂ©nĂ©riques disponibles pour toutes les classes qui y rĂ©fĂšrent. Ça permet notamment d’adjoindre et de partager des comportements gĂ©nĂ©riques par des classes sans passer par le systĂšme classique d’hĂ©ritage. On pourrait Ă©crire trois pages sur le sujet sans le couvrir rĂ©ellement. Toujours est‐il qu’on reste dans l’esprit d’une modification « neutre » du langage au sens oĂč l’on utilise deux fonctionnalitĂ©s dĂ©jĂ  prĂ©sentes, un module et des mĂ©ta‐classes pour proposer l’annotation de type. La prise en charge des annotations a continuĂ© d’évoluer, avec dans Python 3.6 la [PEP 526](https://www.python.org/dev/peps/pep-0526/) — *Une syntaxe pour les annotations de variables*, qui permet dĂ©sormais d’annoter le type d’une variable en plus des arguments d’une fonction. ConcrĂštement, cela prend la forme de : ```python primes: List[int] = [] captain: str # Note: no initial value! class Starship: stats: ClassVar[Dict[str, int]] = {} ``` C’est particuliĂšrement utile lors de l’initialisation de conteneurs vides, pour lesquels l’analyseur de type ne peut savoir quels seront les types stockĂ©s. C’est une standardisation dans le langage d’une fonctionnalitĂ© dĂ©jĂ  prĂ©sente dans _mypy_ qui permettait la mĂȘme chose, mais en s’appuyant sur des commentaires : ```python primes = [] # type: List[int] class Starship: stats = {} # type: ClassVar[Dict[str, int]] ``` Pour en revenir aux annotations, la neutralitĂ© et la gĂ©nĂ©ricitĂ© ont commencĂ© Ă  montrer leur limites lorsque l’on en fait un usage intensif. C’est ce qui est arrivĂ© ces derniĂšres annĂ©es, et qui a motivĂ© deux PEP implĂ©mentĂ©es dans Python 3.7. L’utilisation poussĂ©e du module _typing_ a montrĂ© qu’il Ă©tait plutĂŽt lent, du fait de l’utilisation intensive des mĂ©ta‐classes et notamment de l’hĂ©ritage multiple de mĂ©ta‐classes. C’est pourquoi Python 3.7 introduit la [PEP 560 — Gestion dans le cƓur de Python du module typing et des types gĂ©nĂ©riques](https://www.python.org/dev/peps/pep-0560). Comme le dit son nom, cette PEP intervient dans le cƓur de l’interprĂ©teur CPython, sur des aspects techniques et _hardcore_ pour accĂ©lĂ©rer et simplifier le module `typing`. De son cĂŽtĂ©, la [PEP 563 — Évaluation diffĂ©rĂ©e des annotations](https://www.python.org/dev/peps/pep-0563/), vise Ă  corriger une erreur de jeunesse sur les annotations : celles‐ci sont Ă©valuĂ©es lors du chargement des modules Python. Pour un programme qui contient beaucoup d’annotations, il y a donc un coĂ»t en temps, au dĂ©marrage du programme, alors mĂȘme que les annotations ne sont pas utilisĂ©es. L’autre inconvĂ©nient est que l’évaluation directe ne permettait pas les « rĂ©fĂ©rences par avance » (_forward references_), oĂč l’on dĂ©finit plus bas dans le code un type que l’on souhaite utiliser dĂšs maintenant pour l’annotation. La proposition de la PEP est de stocker la chaĂźne de caractĂšres de l’expression dans le champ `__annotation__`, plutĂŽt que directement le rĂ©sultat de l’expression Ă©valuĂ©e. Pour les outils de vĂ©rification de type, ça ne change rien, car il Ă©tait dĂ©jĂ  possible de stocker une chaĂźne de caractĂšres pour rĂ©soudre, justement, le problĂšme des rĂ©fĂ©rences par avance. Pour d’autres usages des annotations, il faudra forcer un appel `eval(ann, globals, locals)` pour obtenir l’expression de l’annotation. À noter que l’expression n’est plus Ă©valuĂ©e dans son pĂ©rimĂštre d’origine (Ă  l’analyse du module) mais dans le pĂ©rimĂštre qui appelle `eval`, ce qui peut avoir des consĂ©quences si l’expression utilisait des variables du pĂ©rimĂštre local. Pour cette raison, c’est un changement **incompatible avec le passĂ©**. Du fait de cette incompatibilitĂ©, beaucoup de prĂ©cautions sont prises pour l’activation de cette fonctionnalitĂ© : - pour Python 3.7, ce n’est pas actif par dĂ©faut et il faudra une importation explicite pour en bĂ©nĂ©ficier : ```python from __future__ import annotations ``` - pour Python 3.8, l’utilisation d’annotations incompatibles avec la PEP 563 dĂ©clenchera un _PendingDeprecationWarning_, signifiant en gros « attention, bientĂŽt, l’usage sera obsolĂšte » ; on parle ici uniquement de l’usage d’expressions dans les annotations qui dĂ©pendent du pĂ©rimĂštre local, le reste fonctionne trĂšs bien en l’état ; - pour Python 3.9, on passera Ă  un _DeprecationWarning_, signifiant cette fois : « maintenant, cet usage est obsolĂšte » ; - et pour Python 4.0, une erreur sera levĂ©e Ă  la compilation. À noter qu’avec ces deux PEP, les annotations de type rentrent dans le cƓur du langage Python, mĂȘme si elles restent totalement optionnelles. ## AmĂ©lioration du module asyncio Le module `asyncio` a Ă©tĂ© introduit dans Python 3.4 pour gĂ©rer les entrĂ©es‐sorties asynchrones, les boucle d’évĂšnements, les co‐routines et les tĂąches. Dans Python 3.7, `asyncio` a reçu plusieurs nouvelles fonctionnalitĂ©s, ainsi que des amĂ©liorations d’utilisabilitĂ© et de performance. Parmi les nouveautĂ©s, on peut citer la nouvelle fonction `asyncio.run()` qui simplifie l’appel de co‐routines depuis un code synchrone : ```python import asyncio async def bonjour(): print('Bonjour les Moules< !') asyncio.run(bonjour()) ``` Autre nouveautĂ©, `asyncio` accepte maintenant les variables de contexte. Voir la PEP 567 pour plus de dĂ©tails. La nouvelle fonction `asyncio.create_task()` a Ă©tĂ© ajoutĂ©e comme raccourci de `asyncio.get_event_loop().create_task()`. La nouvelle fonction `asyncio.current_task()` retourne la tĂąche courante et la nouvelle fonction `asyncio.all_tasks()` retourne l’ensemble des tĂąches existantes dans une boucle donnĂ©e. Les mĂ©thodes `Task.current_task()` et `Task.all_tasks()` sont devenues obsolĂštes. La nouvelle fonction `asyncio.get_running_loop()` retourne la boucle courante et lance une `RuntimeError` s’il n’y a pas de boucle s’exĂ©cutant actuellement. À la diffĂ©rence de `asyncio.get_event_loop()` qui va crĂ©er une nouvelle boucle plutĂŽt que de lancer une exception. La nouvelle mĂ©thode `StreamWriter.wait_closed()` permet d’attendre jusqu’à la fermeture d’un flux. `StreamWriter.is_closing()` peut ĂȘtre utilisĂ© pour savoir si le flux est en cours de fermeture. La nouvelle mĂ©thode `loop.sock_sendfile()` permet l’envoi d’un fichier en utilisant `os.sendfile` quand c’est possible. Les nouvelles mĂ©thodes `Task.get_loop()` et `Future.get_loop()` retournent leur boucle d’origine. `Server.get_loop()` permet de faire la mĂȘme chose pour les objets `asyncio.Server`. Il est maintenant possible de contrĂŽler le lancement des instances `asyncio.Server`. Auparavant, le serveur se lançait immĂ©diatement aprĂšs sa crĂ©ation. Le nouvel argument `start_serving` de `loop.create_server()` et `loop.create_unix_server()`, ainsi que `Server.start_serving()` et `Server.serve_forever()` peut ĂȘtre utilisĂ© pour dĂ©coupler l’instanciation du serveur et le lancement du serveur. La nouvelle mĂ©thode `Server.is_serving()` retourne `True` si le serveur est lancĂ©. Les objets retournĂ©s par `loop.call_later()` ont maintenant une mĂ©thode `when()` qui retourne leur heure d’exĂ©cution estimĂ©e. Les exceptions lancĂ©es lorsqu’une tĂąche est annulĂ©e ne sont plus journalisĂ©es. Plusieurs API `asyncio` sont devenues obsolĂštes. ## PEP 564 : Gestion des nanosecondes pour le module time AprĂšs avoir permis Ă  Python 3.3 d’avoir une horloge monotone, aprĂšs avoir amĂ©liorĂ© les mĂ©thodes de mesures des _micro‐benchmarks_, Victor Stinner nous propose cette fois d’amĂ©liorer la prĂ©cision des mesures de temps en Python. La [PEP 564](https://www.python.org/dev/peps/pep-0564/) introduit la gestion des nanosecondes dans le module `time`. La prĂ©cision des horloges dans les systĂšmes d’exploitation modernes peut excĂ©der la prĂ©cision du nombre flottant de secondes retournĂ© par la fonction `time.time()`, ainsi que ses diffĂ©rentes variantes. Pour Ă©viter la perte de prĂ©cision, cette PEP ajoute six nouvelles fonctions liĂ©es Ă  la prĂ©cision nanosecondes : * `time.clock_gettime_ns()` ; * `time.clock_settime_ns()` ; * `time.perf_counter_ns()` ; * `time.process_time_ns()` ; * `time.time_ns()`. Des [mesures](https://www.python.org/dev/peps/pep-0564/#annex-clocks-resolution-in-python) montrent que la rĂ©solution de `time.time_ns()` est dĂ©sormais trois fois plus prĂ©cise que celle de `time.time()`. Sur la machine utilisĂ©e pour les _benchmarks_, le plus petit intervalle mesurĂ© s’approche des 300 ns sous Windows et fait moins de 100 ns sous GNU/Linux. ## Message d’erreur ImportError L’erreur `ImportError` va dĂ©sormais afficher un message d’erreur plus explicite en affichant le nom du module et le chemin du fichier utilisĂ© lorsque l’expression `from ... import ...` Ă©choue. ConcrĂštement, avec Python 3.6, on a : ```python>py -3.6>>> from itertools import toto Traceback (most recent call last): File "", line 1, in ImportError: cannot import name 'toto' ``` Avec Python 3.7, c’est mieux : ```python>py -3.7>>> from itertools import toto Traceback (most recent call last): File "", line 1, in ImportError: cannot import name 'toto' from 'itertools' (unknown location) ``` ## PEP 538 : Forçage de la locale C en UTF-8 La [PEP 538](https://www.python.org/dev/peps/pep-0538/) propose d’ajuster le comportement de CPython en prĂ©sence de la _locale_ C vide ou introuvable. Dans ce cas, CPython se comportera comme si l’environnement Ă©tait le suivant : ```bash LC_CTYPE=C.UTF-8 PYTHONIOENCODING=utf-8:surrogateescape ``` Un trĂšs gros travail a Ă©tĂ© fait dans le cycle de Python 3 pour attacher un encodage prĂ©cis Ă  toute chaĂźne de caractĂšres : dans les noms de fichiers, dans les variables d’environnement, etc. Il reste encore quelques cas subtils, et c’est l’objet de cette PEP rĂ©digĂ©e par Nick Coghlan. Dans les cas oĂč la _locale_ C est complĂštement vide, CPython se considĂ©rait en ASCII 7 bits et pouvait gĂ©nĂ©rer facilement des erreurs de conversion. En forçant l’UTF-8 dans ces situations, CPython devient Ă  mĂȘme de mieux gĂ©rer le problĂšme et de mieux interagir avec les autres modules qui s’attendent tous Ă  travailler en encodage 8 bits. Lorsque CPython rĂ©alise cet ajustement, il force la variable d’environnement `LC_TYPE` ce qui a pour effet important que toutes les bibliothĂšques chargĂ©es dynamiquement depuis l’interprĂ©teur et tous les processus lancĂ©s depuis l’interprĂ©teur hĂ©ritent de ce changement. Cela permet notamment de configurer correctement _GNU readline_, dont le comportement dĂ©pend de la _locale_ en cours. À l’intĂ©rieur de la PEP, Nick liste des cas concrets oĂč cela peut se prĂ©senter aujourd’hui et oĂč cette PEP fait la diffĂ©rence : * lors de l’utilisation de technologies de conteneurs : _Docker_, _Kubernetes_, _OpenShift_, mais aussi _GNOME Flatpak_ ou _Ubuntu Snappy_ ; * lors d’un _ssh_ vers un serveur, lorsque la _locale_ du PC initiant la connexion est exportĂ©e en tant que variable d’environnement mais n’existe pas sur le serveur. Un pas de plus vers l’universalitĂ© d’Unicode ! ## PEP 540 : Forçage de l’UTF-8 Ă  l’exĂ©cution La [PEP 540](https://www.python.org/dev/peps/pep-0540/) adresse un problĂšme similaire Ă  la PEP prĂ©cĂ©dente, mais avec des cas d’usage lĂ©gĂšrement diffĂ©rents. Deux changements sont proposĂ©s : 1. permettre le forçage de l’utilisation d’UTF-8 par CPython, en ignorant la _locale_ ; ceci peut ĂȘtre activĂ© soit en passant un paramĂštre au lancement de l’interprĂ©teur (`-X UTF8`), soit en fixant la variable d’environnement `PYTHONUTF8` Ă  `1` ; 2. activer ce forçage lorsque la _locale_ est fixĂ©e Ă  `C` (POSIX) ; ceci rejoint le comportement de la PEP prĂ©cĂ©dente. Les effets du forçage d’UTF-8 : * `sys.getfilesystemencoding()` retourne systĂ©matiquement `UTF-8`, en ignorant la _locale_ ; * `locale.getpreferredencoding()` retourne systĂ©matiquement `UTF-8`, en ignorant la _locale_ et le paramĂštre _do_setlocale_ ; * `sys.stdin`, `sys.stdout` et `sys.stderr` utilisent l’encodage `UTF-8` avec la gestion d’erreur _surrogateescape_ pour les entrĂ©es et sorties standards, et _backslashreplace_ pour la sortie erreur standard. Ces deux PEP permettent d’ajuster le comportement de CPython lorsque la _locale_ est configurĂ©e diffĂ©remment pour un systĂšme. La diffĂ©rence principale entre les deux approches est que le forçage d’UTF-8 n’affecte que l’interprĂ©teur en cours, il n’est pas hĂ©ritĂ© par les autres modules dynamiques du mĂȘme environnement ou par les sous‐processus lancĂ©s. Les deux PEP sont donc complĂ©mentaires. ## PEP 552 : Des .pyc basĂ©s sur les hashes La compilation des modules Python en _bytecode_ est stockĂ©e dans un fichier `.pyc` dans le rĂ©pertoire `__pycache__`. En informatique, lorsque l’on parle de cache, il se pose toujours la question dĂ©licate de l’invalidation du cache, et Python ne fait pas exception. Python a choisi jusqu’à prĂ©sent de stocker des horodatages (_timestamps_) dans le `.pyc`. Lors de l’exĂ©cution, l’interprĂ©teur regarde la date de modification du module Python, la date stockĂ©e dans le `.pyc` et si cette derniĂšre est plus ancienne, il recompile le module. L’approche a plutĂŽt bien marchĂ© pour les vingt‐quatre derniĂšres annĂ©es, mais il se trouve des cas oĂč ce n’est pas appropriĂ© : 1. lorsque l’horodatage des fichiers n’est pas complĂštement fiable ou prĂ©cis (salut NFS, salut les partages rĂ©seaux Windows !) ; 2. lorsque l’on veut crĂ©er des [_builds_ reproductibles](https://reproducible-builds.org/), c’est‐à‐dire construire un logiciel de façon Ă  ce que, pour des donnĂ©es d’entrĂ©e identiques, les donnĂ©es de sortie soient identiques ; faire dĂ©pendre le choix de recompiler un module d’une date de modification d’un fichier altĂšre cette reproductibilitĂ©. La solution proposĂ©e et implĂ©mentĂ©e par la [PEP 552](https://www.python.org/dev/peps/pep-0552/) est de stocker un condensat (_hash_) du fichier source dans le `.pyc`, en lieu et place de l’horodatage. L’algorithme de hachage choisi est _SipHash_, parce qu’il est dĂ©jĂ  disponible dans l’interprĂ©teur. L’interprĂ©teur CPython ne gĂ©nĂ©rera jamais spontanĂ©ment de `.pyc` basĂ© sur les _hashes_. Pour obtenir de tels `.pyc`, il faut dĂ©clencher soi‐mĂȘme la compilation avec les modules `compileall` ou `py_compile`. Deux types de `.pyc` basĂ©s sur les _hashes_ ont Ă©tĂ© dĂ©finis : * les vĂ©rifiĂ©s, pour lesquels CPython va recalculer le _hash_ du module source et vĂ©rifier si un changement a eu lieu ; * les non‐vĂ©rifiĂ©s, pour lesquels CPython se contente de charger le module ; cela correspond Ă  des environnements ou un autre programme est chargĂ© de vĂ©rifier et gĂ©nĂ©rer les `.pyc` en fonction de l’évolution des sources. ## PEP 562 : Extension de l’accĂšs aux attributs de module Avec la [PEP 562](https://www.python.org/dev/peps/pep-0562/), Python 3.7 permet de dĂ©finir une fonction `__getattr__()` pour les modules. Cette fonction sera appelĂ©e lorsque l’attribut d’un module n’est pas trouvĂ©, selon le mĂȘme principe que `__getattr__()` pour les classes. Il est Ă©galement possible de dĂ©finir la fonction `__dir__()` qui sera appelĂ©e lorsque l’utilisateur liste le contenu du module (avec `dir()`). Un exemple typique d’utilisation de ces deux fonctionnalitĂ©s est la possibilitĂ© de gĂ©rer l’obsolescence de certaines fonctions du module, ou encore de permettre un chargement « Ă  la demande » (_lazy loading_). Exemple d’émission d’alerte (_warning_) pour des fonctions obsolĂštes : ```python # monmodule.py from warnings import warn deprecated_names = ["old_function", ...] def _deprecated_old_function(arg, other): ... def new_function(): ... def __getattr__(name): if name in deprecated_names: warn(f"{name} is deprecated", DeprecationWarning) return globals()[f"_deprecated_{name}"] raise AttributeError(f"module {__name__} has no attribute {name}") def __dir__(): return ["new_function"]+ deprecated_names # main.py from monmodule import old_function # fonctionne, mais Ă©met un warning print(dir(monmodule)) # affiche ["new_function", "old_function" ] # avant python 3.7, cela aurait affichĂ© ["_deprecated_old_function", "new_function", ...] ``` ## PEP 565 : Meilleure gestion des alertes d’API obsolĂštes Avec la [PEP 565](https://www.python.org/dev/peps/pep-0565/), Python 3.7 fait des ajustements Ă  la marge sur la gestion des alertes (_warnings_) lors de l’usage d’API obsolĂštes. Une gestion appropriĂ©e de ce type d’alerte n’est pas facile Ă  trouver et les dĂ©veloppeurs de Python cherchent le bon niveau de compromis. Python dispose de trois types principaux d’alertes Ă  lever pour les API qui sont sur le chemin de l’obsolescence : * `PendingDeprecationWarning`, utilisĂ© pour les API qui deviendront prochainement obsolĂštes ; * `DeprecationWarning`, utilisĂ© pour les API qui sont obsolĂštes et disparaĂźtront dans le futur ; * `FutureWarning`, utilisĂ© pour les constructions syntaxiques dont la construction va changer dans le futur. Ces alertes sont levĂ©es sous forme de messages sur la sortie d’erreur mais n’affectent pas le programme outre mesure. L’étape aprĂšs `DeprecationWarning` est de lever une exception, qui cette fois arrĂȘte le programme en cours d’exĂ©cution. Jusqu’à Python 2.6 et 3.1 , le comportement par dĂ©faut Ă©tait de cacher les `PendingDeprecationWarning` et d’afficher les autres. Un mode dĂ©veloppeur pouvait ĂȘtre activĂ© avec `-Wdefault`, dans lequel Python affichait aussi les `PendingDeprecationWarning`, ce mode Ă©tant notamment activĂ© par le module _unittest_. L’idĂ©e Ă©tait que les dĂ©veloppeurs utilisent le mode `-Wdefault`, et que les utilisateurs d’un programme ou d’une bibliothĂšque en Python voient uniquement les `FutureWarning` et `DeprecationWarning`. À l’usage, les dĂ©veloppeurs de Python ont constatĂ© qu’un nombre croissant d’utilisateurs de bibliothĂšques ou programmes Ă©crits en Python Ă©taient confrontĂ©s Ă  des alertes `DeprecationWarning`, pour lesquelles ils ne pouvaient rien : elles Ă©taient levĂ©es par des dĂ©pendances de leur code, sur lesquelles ils n’avaient pas de contrĂŽle. Cela correspondait en gĂ©nĂ©ral Ă  une situation oĂč une bibliothĂšque avait Ă©tĂ© validĂ©e et livrĂ©e avec une version de Python plus ancienne, dans laquelle cette alerte n’existait pas encore. La dĂ©cision a donc Ă©tĂ© prise pour Python 2.7 et 3.2 d’ignorer les alertes `DeprecatonWarning` par dĂ©faut, tout comme les `PendingDeprecationWarning`. Il faut activer le mode `-Wdefault` pour revoir ces deux types d’alertes. Cependant, ce changement a rendu ces alertes trop discrĂštes et des dĂ©veloppeurs ont Ă©tĂ© surpris de la disparition de certaines API dans de nouvelles versions de Python, alors que leur disparition avait Ă©tĂ© prĂ©parĂ©e. La PEP 565 propose un compromis plus subtil pour gĂ©rer la situation : afficher les `DeprecationWarning` lors de l’exĂ©cution du module principal. Le module principal s’entend comme le module `__main__` pour un script d’un seul fichier ou le code entrĂ© dans l’interprĂ©teur interactif. D’autres changements plus lĂ©gers sont inclus dans cette PEP : * la signification de `FutureWarning` est Ă©tendue aux alertes destinĂ©es aux **utilisateurs** d’une application, pour les prĂ©venir d’une utilisation en passe de devenir obsolĂšte (on peut imaginer par exemple un rĂ©glage particulier d’une application qui n’a plus de sens) ; * la documentation sur les alertes devient beaucoup plus dĂ©taillĂ©e, avec la liste complĂšte des options en ligne de commande pour les contrĂŽler, le dĂ©tail du filtre par dĂ©faut et pas mal d’exemples pour montrer comment tester la gĂ©nĂ©ration des alertes ; * il y a maintenant une recommandation officielle Ă  destination des dĂ©veloppeurs d’outils de tests, d’activer les alertes dĂ©veloppeur lors de l’exĂ©cution d’une suite de tests ; * de mĂȘme, les dĂ©veloppeurs de « ligne de commande interactive » (shell), tel que par exemple _IPython_, sont priĂ©s de configurer les alertes afin d’afficher les `DeprecationWarning` pour les commandes entrĂ©es interactivement. ## Le nouveau mode d’exĂ©cution « dev » La ligne de commande a maintenant une option en plus, `-X dev` qui active le mode _dĂ©veloppement_ de CPython (Ă©galement activable via la variable d’environnement `PYTHONDEVMODE`). Dans ce mode, CPython rĂ©alise des vĂ©rifications supplĂ©mentaires Ă  l’exĂ©cution, qui sont trop consommatrices pour ĂȘtre activĂ©es par dĂ©faut : * affichage de tous les types d’alertes (y compris le _DeprecationWarning_ citĂ© plus haut) ; * activation des traceurs mĂ©moire pour les allocations, _cf._ [`PyMem_SetupDebugHooks()`](https://docs.python.org/3/c-api/memory.html#c.PyMem_SetupDebugHooks) ; * activation du module [_faulthandler_](https://docs.python.org/3/library/faulthandler.html#module-faulthandler) qui permet d’afficher la pile d’appel lors d’un crash ; * activation du [mode dĂ©bogage d’_asyncio_](https://docs.python.org/3/library/asyncio-dev.html#asyncio-debug-mode). # AmĂ©lioration de l’API C ## PEP 539 : Introduction d’une nouvelle API C pour le stockage interne Ă  un thread La [PEP 539](https://www.python.org/dev/peps/pep-0539/) propose une nouvelle API pour le stockage de donnĂ©es privĂ©es pour un fil d’exĂ©cution (_Thread Local Storage_ ou _TLS_). Il existait dĂ©jĂ  une telle API dans CPython, mais celle‐ci souffrait du problĂšme suivant : la clef utilisĂ©e pour chercher des valeurs spĂ©cifiques Ă  un fil d’exĂ©cution Ă©tait un _int_. C’est contraire Ă  la norme POSIX _pthreads_, qui exige un type opaque _pthread_key_t_. Cela n’est pas un problĂšme pour les plates‐formes oĂč le type _pthread_key_t_ peut se convertir facilement en _int_, comme GNU/Linux (oĂč c’est un _unsigned int_) ou Windows (oĂč c’est un _DWORD_). Cependant, d’autres plates‐formes existent, qui sont compatibles POSIX, et pour lesquelles l’API existante ne peut pas fonctionner : Cygwin et CloudAPI, par exemple. L’API actuelle de stockage interne Ă  un fil d’exĂ©cution est donc marquĂ©e comme Ă©tant obsolĂšte, et une nouvelle API compatible POSIX la remplace. # CommunautĂ© ## PEP 545 : Officialisation des traductions de la documentation La [PEP 545](https://www.python.org/dev/peps/pep-0545/) dĂ©crit le processus de traduction de la documentation Python. Trois traductions sont dĂ©sormais hĂ©bergĂ©es sur _python.org_ : * la [documentation en français](https://docs.python.org/fr/3/) ; * la [documentation en japonais](https://docs.python.org/ja/3/) ; * la [documentation en corĂ©en](https://docs.python.org/ko/3/). La PEP permet de mettre en valeur les efforts fait par diffĂ©rentes communautĂ©s pour traduire la documentation, et permettra d’uniformiser le travail fait pour d’autres langues : espagnol, chinois, etc. On en profite pour faire appel Ă  des contributeurs : la traduction française est aujourd’hui Ă  29 % et pourrait recevoir plus de contributeurs. Ça se passe [sur GitHub](https://github.com/python/python-docs-fr). # Liens complĂ©mentaires Toutes les nouvelles PEP introduites : * [PEP 538](https://www.python.org/dev/peps/pep-0538/) : Force l’utilisation de la _locale_ C historique Ă  une _locale_ UTF-8 ; * [PEP 539](https://www.python.org/dev/peps/pep-0539/) : Nouvelle API C pour ajouter une mĂ©moire locale de fil d’exĂ©cution, ou _Thread Local Storage_ (TLS) ; * [PEP 540](https://www.python.org/dev/peps/pep-0540/) : Ajout d’un nouveau mode UTF-8 ; * [PEP 545](https://www.python.org/dev/peps/pep-0545/) : Officialisation du processus de traduction de la documentation ; * [PEP 552](https://www.python.org/dev/peps/pep-0552) : ReproductibilitĂ© des fichiers .pyc ; * [PEP 557](https://www.python.org/dev/peps/pep-0557) : Introduction des _dataclasses_ ; * [PEP 560](https://www.python.org/dev/peps/pep-0560) : Gestion dans le cƓur de Python du module typing et des types gĂ©nĂ©riques ; * [PEP 562](https://www.python.org/dev/peps/pep-0562) : Extension de l’accĂšs aux attributs de module ; * [PEP 563](https://www.python.org/dev/peps/pep-0563) : Évaluation diffĂ©rĂ©e des annotations ; * [PEP 564](https://www.python.org/dev/peps/pep-0564) : Gestion des nanosecondes pour le module _time_ ; * [PEP 565](https://www.python.org/dev/peps/pep-0565) : Meilleure gestion des alertes d’API obsolĂštes ; * [PEP 567](https://www.python.org/dev/peps/pep-0567) : Variables contextualisĂ©es.

AltStyle ă«ă‚ˆăŁăŠć€‰æ›ă•ă‚ŒăŸăƒšăƒŒă‚ž (->ă‚ȘăƒȘă‚žăƒŠăƒ«) /