IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Python 3.11 est disponible et s'accompagne d'une amélioration de la vitesse, de meilleures gestion des erreurs,
Du type self ainsi que des notes d'exception

Le , par Stéphane le calme

48PARTAGES

16  0 
Le journal des modifications de Python 3.11 consiste en une longue liste de corrections de bogues, d'améliorations et d'ajouts, dont la plupart ne seront peut-être même pas remarqués. Cependant, quelques nouvelles fonctionnalités critiques pourraient considérablement améliorer votre flux de travail Python, notamment l'amélioration de la vitesse, de meilleures gestion des erreurs (notamment au niveau des messages), des notes pour les exceptions, du type self (que vous pouvez ajouter à la définition d'une fonction si sa valeur de retour est du même type que la classe elle-même ou une nouvelle instance de la classe), des améliorations des bibliothèques standard.


Un langage qui gagne en popularité

Depuis un an déjà, Python occupe la première place de l'index TIOBE. Lors de son arrivée en pole position, Paul Jansen, PDG de Tiobe, notait déjà que c'était une première en 20 ans :

« Pour la première fois depuis plus de 20 ans, nous avons un nouveau chef de file : le langage de programmation Python. L'hégémonie de longue date de Java et C est terminée. Python, qui a commencé comme un simple langage de script, comme alternative à Perl, est devenu mature. Sa facilité d'apprentissage, son énorme quantité de bibliothèques et son utilisation répandue dans toutes sortes de domaines en ont fait le langage de programmation le plus populaire d'aujourd'hui. Félicitations Guido van Rossum ! Proficiat ! »

Python est un langage de programmation interprété, multi-paradigme et multi-plateformes. Il favorise la programmation impérative structurée, fonctionnelle et orientée objet. Il est doté d'un typage dynamique fort, d'une gestion automatique de la mémoire par récupérateur de mémoire et d'un système de gestion d'exceptions ; il ressemble ainsi à Perl, Ruby, Scheme, Smalltalk et Tcl.

Python gagne en popularité ces temps-ci, en partie à cause de l'essor de la science des données et de son écosystème de bibliothèques logicielles d'apprentissage automatique comme NumPy, Pandas, TensorFlow de Google et PyTorch de Facebook.

En effet, Python continuerait d'être la norme et la compétence la plus recherchée dans le domaine de la science des données, dépassant de loin les autres technologies et outils, comme R, SAS, Hadoop et Java. C'est ce que suggère une analyse réalisée par Terence Shin, un spécialiste des données, qui a indiqué que l'adoption de Python pour la science des données continue de croître alors même que le langage R, plus spécialisé, est en déclin. Bien entendu, cela ne veut pas dire que les spécialistes des données vont abandonner R de sitôt. L'on continuera probablement à voir Python et R utilisés pour leurs forces respectives.


Python 3.11 gagne en rapidité grâce à un interpréteur adaptatif spécialisé

Au cours de l'année écoulée, Microsoft a financé une équipe - dirigée par les principaux développeurs Mark Shannon et Guido van Rossum - pour travailler à plein temps sur l'accélération de CPython, la nouvelle version de l'interpréteur Python standard. Avec un financement supplémentaire de Bloomberg et l'aide d'un large éventail d'autres contributeurs de la communauté, les résultats ont porté leurs fruits. Sur les benchmarks pyperformance au moment de la sortie de la version bêta, Python 3.11 était environ 1,25 fois plus rapide que Python 3.10, une réalisation phénoménale.

Mais il reste encore beaucoup à faire. Lors du Python Language Summit 2022, Mark Shannon a présenté la prochaine étape du projet Faster CPython. L'avenir est rapide.

Le premier problème soulevé par Shannon était un problème de mesures. Afin de savoir comment rendre Python plus rapide, nous devons savoir à quel point Python est actuellement lent. Mais lent à faire quoi, exactement ? Et à quel point ?

De bons benchmarks sont essentiels pour un projet qui vise à optimiser Python pour une utilisation générale. Pour cela, l'équipe Faster CPython a besoin de l'aide de la communauté dans son ensemble. Le projet « a besoin de plus de repères », a déclaré Shannon - il doit comprendre plus précisément pourquoi la base d'utilisateurs dans son ensemble utilise Python, comment ils le font et ce qui le rend lent pour le moment (si c'est lent !) .

Une référence, a expliqué Shannon, est « juste un programme que nous pouvons chronométrer ». Toute personne ayant une référence - ou même simplement une suggestion de référence ! – qu'elle pense être représentatif d'un projet plus vaste sur lequel elle travaille est invitée à les soumettre au suivi des problèmes du référentiel python/pyperformance sur GitHub.

Néanmoins, l'équipe Faster CPython a de quoi s'occuper entre-temps.

Une grande partie du travail d'optimisation dans 3.11 a été réalisée grâce à la mise en œuvre de PEP 659, un « interpréteur adaptatif spécialisé ». L'interpréteur adaptatif que Shannon et son équipe ont introduit suit les bytecodes individuels à différents moments de l'exécution d'un programme. Lorsqu'il repère une opportunité, un bytecode peut être « accéléré » : cela signifie qu'un bytecode lent, qui peut faire beaucoup de choses, est remplacé par l'interpréteur par un bytecode plus spécialisé qui est très bon pour faire une chose spécifique.

Shannon a noté que Python a également essentiellement la même consommation de mémoire en 3.11 qu'en 3.10. C'est quelque chose sur lequel il aimerait travailler : une surcharge de mémoire plus petite signifie généralement moins d'opérations de comptage de références dans la machine virtuelle, une surcharge de collecte de mémoire plus faible et des performances plus fluides en conséquence.

Une autre grande piste d'optimisation restante est la question des extensions C. L'interface simple de CPython avec C est son principal avantage par rapport aux autres implémentations Python telles que PyPy, où les incompatibilités avec les extensions C sont l'un des plus grands obstacles à l'adoption par les utilisateurs. Le travail d'optimisation qui a été fait dans CPython 3.11 a largement ignoré la question des modules d'extension, mais Shannon veut maintenant ouvrir la possibilité d'exposer des API de fonction de bas niveau à la machine virtuelle, réduisant ainsi le temps de communication entre le code Python et Code C.

Meilleure gestion des erreurs

Python 3.10 nous a donné de meilleurs messages d'erreur à divers égards, mais Python 3.11 vise à les améliorer encore plus. Certaines des choses les plus importantes qui sont ajoutées aux messages d'erreur dans Python 3.11 sont :

Emplacements exacts des erreurs dans les retraçages

Jusqu'à présent, dans un traçage, la seule information que vous obteniez sur l'endroit où une exception a été déclenchée était la ligne. Le problème aurait pu être n'importe où sur la ligne, donc parfois cette information n'était pas suffisante.

Voici un exemple :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def get_margin(data): 
    margin = data['profits']['monthly'] / 10 + data['profits']['yearly'] / 2 
    return margin 
  
data = { 
    'profits': { 
        'monthly': 0.82, 
        'yearly': None, 
    }, 
    'losses': { 
        'monthly': 0.23, 
        'yearly': 1.38, 
    }, 
} 
print(get_margin(data))

Ce code génère une erreur, car l'un de ces champs dans le dictionnaire est None. Voici ce que nous obtenons :

Citation Envoyé par Affichage à l'écran
Traceback (most recent call last):
File "/Users/tusharsadhwani/code/marvin-python/mytest.py", line 15, in <module>
print(get_margin(data))
File "/Users/tusharsadhwani/code/marvin-python/mytest.py", line 2, in print_margin
margin = data['profits']['monthly'] / 10 + data['profits']['yearly'] / 2
TypeError: unsupported operand type(s) for /: 'NoneType' and 'int'

Mais il est impossible de dire par le retraçage lui-même, quelle partie du calcul a causé l'erreur.

Sur la version 3.11 cependant :

Citation Envoyé par Affichage à l'écran
Traceback (most recent call last):
File "asd.py", line 15, in <module>
print(get_margin(data))
^^^^^^^^^^^^^^^^
File "asd.py", line 2, in print_margin
margin = data['profits']['monthly'] / 10 + data['profits']['yearly'] / 2
~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
TypeError: unsupported operand type(s) for /: 'NoneType' and 'int'

Il est évident que data['profits']['yearly'] était None.

Pour pouvoir restituer ces informations, les données end_line et end_col ont été ajoutées aux objets de code Python. Vous pouvez également accéder à ces informations directement via la méthode obj.__code__.co_positions().

Les notes pour les exceptions

Pour rendre les traces encore plus riches en contexte, Python 3.11 vous permet d'ajouter des notes aux objets d'exception, qui sont stockées dans les exceptions et affichées lorsque l'exception est déclenchée.

Prenez ce code par exemple, où nous ajoutons des informations importantes sur une logique de conversion de données d'API :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def get_seconds(data): 
    try: 
        milliseconds = float(data['milliseconds']) 
    except ValueError as exc: 
        exc.add_note( 
            "The time field should always be a number, this is a critial bug. " 
            "Please report this to the backend team immediately." 
        ) 
        raise  # re-raises the exception, instead of silencing it 
  
    seconds = milliseconds / 1000 
    return seconds 
  
get_seconds({'milliseconds': 'foo'})  # 'foo' is not a number!

Cette note ajoutée est imprimée juste en dessous du message d'exception :

Citation Envoyé par Affichage à l'écran
Traceback (most recent call last):
File "asd.py", line 14, in <module>
get_seconds({"milliseconds": "foo"})
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "asd.py", line 3, in get_seconds
milliseconds = float(data["milliseconds"])
^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: could not convert string to float: 'foo'
The time field should always be a number, this is a critial bug. Please report this to the backend team immediately.

Prise en charge toml intégrée

La bibliothèque standard a maintenant un support intégré pour lire les fichiers TOML, en utilisant le module tomllib :

Code Python : Sélectionner tout
1
2
3
4
import tomllib 
  
with open('.deepsource.toml', 'rb') as file: 
    data = tomllib.load(file)

tomllib est en fait basé sur une bibliothèque d'analyse TOML open source appelée tomli. Et actuellement, seule la lecture des fichiers TOML est prise en charge. Si vous devez plutôt écrire des données dans un fichier TOML, envisagez d'utiliser le package tomli-w.

Groupes de travail asynchrones

Lorsque vous faites de la programmation asynchrone, vous rencontrez souvent des situations où vous devez déclencher de nombreuses tâches à exécuter simultanément, puis prendre des mesures lorsqu'elles sont terminées. Par exemple, télécharger un tas d'images en parallèle, puis les regrouper dans un fichier zip à la fin.

Pour ce faire, vous devez collecter des tâches et les transmettre à asyncio.gather. Voici un exemple simple de tâches exécutées en parallèle avec la fonction de gather :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import asyncio 
  
async def simulate_flight(city, departure_time, duration): 
    await asyncio.sleep(departure_time) 
    print(f"Flight for {city} departing at {departure_time}PM") 
  
    await asyncio.sleep(duration) 
    print(f"Flight for {city} arrived.") 
  
  
flight_schedule = { 
    'boston': [3, 2], 
    'detroit': [7, 4], 
    'new york': [1, 9], 
} 
  
async def main(): 
    tasks = [] 
    for city, (departure_time, duration) in flight_schedule.items(): 
        tasks.append(simulate_flight(city, departure_time, duration)) 
  
    await asyncio.gather(*tasks) 
    print("Simulations done.") 
  
asyncio.run(main())

Mais devoir maintenir une liste des tâches soi-même pour pouvoir les attendre est un peu maladroit. Aussi, une nouvelle API est ajoutée à asyncio appelée Groupes de tâches :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import asyncio 
  
async def simulate_flight(city, departure_time, duration): 
    await asyncio.sleep(departure_time) 
    print(f"Flight for {city} departing at {departure_time}PM") 
  
    await asyncio.sleep(duration) 
    print(f"Flight for {city} arrived.") 
  
  
flight_schedule = { 
    'boston': [3, 2], 
    'detroit': [7, 4], 
    'new york': [1, 9], 
} 
  
async def main(): 
    async with asyncio.TaskGroup() as tg: 
        for city, (departure_time, duration) in flight_schedule.items(): 
            tg.create_task(simulate_flight(city, departure_time, duration)) 
  
    print("Simulations done.") 
  
asyncio.run(main())

Lorsque le gestionnaire de contexte asyncio.TaskGroup() se ferme, il s'assure que toutes les tâches créées à l'intérieur ont fini de s'exécuter.


Groupes d'exceptions

Une fonctionnalité similaire a également été ajoutée pour la gestion des exceptions dans les tâches asynchrones, appelées groupes d'exceptions.

Supposons que de nombreuses tâches asynchrones s'exécutent ensemble et que certaines d'entre elles génèrent des erreurs. Actuellement, le système de gestion des exceptions de Python ne fonctionne pas bien dans ce scénario.

Voici une courte démo de ce à quoi cela ressemble avec 3 tâches simultanées qui ont planté :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
import asyncio 
  
def bad_task(): 
    raise ValueError("oops") 
  
async def main(): 
    tasks = [] 
    for _ in range(3): 
        tasks.append(asyncio.create_task(bad_task())) 
  
    await asyncio.gather(*tasks) 
  
asyncio.run(main())

Lorsque vous exécutez ce code :

Citation Envoyé par Affichage à l'écran
$ python asd.py
Traceback (most recent call last):
File "asd.py", line 13, in <module>
asyncio.run(main())
File "/usr/bin/python3.8/lib/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/bin/python3.8/lib/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "asd.py", line 9, in main
tasks.append(asyncio.create_task(bad_task()))
File "asd.py", line 4, in bad_task
raise ValueError("oops")
ValueError: oops

Rien n'indique que 3 de ces tâches s'exécutaient ensemble. Dès que la première échoue, elle fait planter tout le programme.

Mais en Python 3.11, le comportement est un peu meilleur :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
import asyncio 
  
async def bad_task(): 
    raise ValueError("oops") 
  
async def main(): 
    async with asyncio.TaskGroup() as tg: 
        for _ in range(3): 
            tg.create_task(bad_task()) 
  
asyncio.run(main())
Citation Envoyé par Affichage à l'écran
$ python asd.py
+ Exception Group Traceback (most recent call last):
| File "<stdin>", line 1, in <module>
| File "/usr/local/lib/python3.11/asyncio/runners.py", line 181, in run
| return runner.run(main)
| ^^^^^^^^^^^^^^^^
| File "/usr/local/lib/python3.11/asyncio/runners.py", line 115, in run
| return self._loop.run_until_complete(task)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| File "/usr/local/lib/python3.11/asyncio/base_events.py", line 650, in run_until_complete
| return future.result()
| ^^^^^^^^^^^^^^^
| File "<stdin>", line 2, in main
| File "/usr/local/lib/python3.11/asyncio/taskgroups.py", line 139, in __aexit__
| raise me from None
| ^^^^^^^^^^^^^^^^^^
| ExceptionGroup: unhandled errors in a TaskGroup (3 sub-exceptions)
+-+---------------- 1 ----------------
| Traceback (most recent call last):
| File "<stdin>", line 2, in bad_task
| ValueError: oops
+---------------- 2 ----------------
| Traceback (most recent call last):
| File "<stdin>", line 2, in bad_task
| ValueError: oops
+---------------- 3 ----------------
| Traceback (most recent call last):
| File "<stdin>", line 2, in bad_task
| ValueError: oops
+------------------------------------

L'exception nous indique maintenant que trois erreurs ont été générées, dans une structure appelée ExceptionGroup.

La gestion des exceptions avec ces groupes d'exceptions est également intéressante, vous pouvez soit faire except ExceptionGroup pour intercepter toutes les exceptions en une seule fois :

Code Python : Sélectionner tout
1
2
3
4
try: 
    asyncio.run(main()) 
except ExceptionGroup as eg: 
    print(f"Caught exceptions: {eg}")
Citation Envoyé par Affichage à l'écran
$ python asd.py
Caught exceptions: unhandled errors in a TaskGroup (3 sub-exceptions)

Ou vous pouvez les intercepter en fonction du type d'exception, en utilisant la nouvelle syntaxe except* :

Code Python : Sélectionner tout
1
2
3
4
try: 
    asyncio.run(main()) 
except* ValueError as eg: 
    print(f"Caught ValueErrors: {eg}")
Citation Envoyé par Affichage à l'écran
$ python asd.py
Caught ValueErrors: unhandled errors in a TaskGroup (3 sub-exceptions)

Améliorations apportées au module typing

Le module typing a vu beaucoup de mises à jour intéressantes dans cette version. Voici quelques-uns des plus intéressantes :

Génériques variadiques

La prise en charge des génériques variadiques a été ajoutée au module typing dans Python 3.11.

Cela signifie que vous pouvez désormais définir des types génériques pouvant contenir un nombre arbitraire de types. Il est utile pour définir des méthodes génériques pour les données multidimensionnelles.

Par exemple:

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from typing import Generic 
from typing_extensions import TypeVarTuple, Unpack 
  
Shape = TypeVarTuple('Shape') 
  
class Array(Generic[Unpack[Shape]]): 
    ... 
  
# holds 1 dimensional data, like a regular list 
items: Array[int] = Array() 
  
# holds 3 dimensional data, for example, X axis, Y axis and value 
market_prices: Array[int, int, float] = Array() 
  
# This function takes in an `Array` of any shape, and returns the same shape 
def double(array: Array[Unpack[Shape]]) -> Array[Unpack[Shape]]: 
    ... 
  
# This function takes an N+2 dimensional array and reduces it to an N dimensional one 
def get_values(array: Array[int, int, *Shape]) -> Array[*Shape]: 
    ... 
  
# For example: 
vector_space: Array[int, int, complex] = Array() 
reveal_type(get_values(vector_space))  # revealed type is Array[complex]

Les génériques variadiques peuvent être très utiles pour définir des fonctions qui mappent sur des données à N dimensions. Cette fonctionnalité peut être très utile pour la vérification de type des bases de code qui s'appuient sur des bibliothèques de science des données telles que numpy ou tensorflow.

L'équipe responsable du développement de Python explique que : « La nouvelle syntaxe Generic[*Shape] n'est prise en charge que dans Python 3.11. Pour utiliser cette fonctionnalité dans Python 3.10 et versions antérieures, vous pouvez utiliser la fonction intégrée typing.Unpack à la place de Generic[Unpack[Shape]] ».

singledispatch prend désormais en charge les unions

functools.singledispatch est un moyen pratique de surcharger les fonctions en Python, basé sur des indications de type. Cela fonctionne en définissant une fonction générique et en se servant de @singledispatch. Ensuite, vous pouvez définir des variantes spécialisées de cette fonction, en fonction du type des arguments de la fonction :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from functools import singledispatch 
  
  
@singledispatch 
def half(x): 
    """Returns the half of a number""" 
    return x / 2 
  
@half.register 
def _(x: int): 
    """For integers, return an integer""" 
    return x // 2 
  
@half.register 
def _(x: list): 
    """For a list of items, get the first half of it.""" 
    list_length = len(x) 
    return x[: list_length // 2] 
  
                            # Outputs: 
print(half(3.6))            # 1.8 
print(half(15))             # 7 
print(half([1, 2, 3, 4]))   # [1, 2]

En inspectant le type donné aux arguments de la fonction, singledispatch peut créer des fonctions génériques, fournissant une manière non orientée objet de faire la surcharge de fonction.

Mais ce sont toutes de vieilles nouvelles. Ce que Python 3.11 apporte, c'est que maintenant, vous pouvez passer des types d'union pour ces arguments. Par exemple, pour enregistrer une fonction pour tous les types de nombres, vous deviez auparavant le faire séparément pour chaque type, tel que float, complex ou Decimal :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
@half.register 
def _(x: float): 
    return x / 2 
  
@half.register 
def _(x: complex): 
    return x / 2 
  
@half.register 
def _(x: decimal.Decimal): 
    return x / 2

Mais maintenant, vous pouvez tous les spécifier dans une Union :

Code Python : Sélectionner tout
1
2
3
@half.register 
def _(x: float | complex | decimal.Decimal): 
    return x / 2

Et le code fonctionnera exactement comme prévu.

Le type self

Auparavant, si vous deviez définir une méthode de classe qui renvoyait un objet de la classe elle-même, ajouter des types pour cela était un peu bizarre, cela ressemblerait à ceci :

Code TypeScript : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
from typing import TypeVar 
  
T = TypeVar('T', bound=type) 
  
class Circle: 
    def __init__(self, radius: int) -> None: 
        self.radius = radius 
  
    @classmethod 
    def from_diameter(cls: T, diameter) -> T: 
        circle = cls(radius=diameter/2) 
        return circle

Pour pouvoir dire qu'une méthode retourne le même type que la classe elle-même, il fallait définir un TypeVar, et dire que la méthode retourne le même type T que la classe actuelle elle-même.

Mais avec le type Self, rien de tout cela n'est nécessaire :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
from typing import Self 
  
class Circle: 
    def __init__(self, radius: int) -> None: 
        self.radius = radius 
  
    @classmethod 
    def from_diameter(cls, diameter) -> Self: 
        circle = cls(radius=diameter/2) 
        return circle

Required[] and NotRequired[]

TypedDict est vraiment utile pour ajouter des informations de type à une base de code qui utilise beaucoup de dictionnaires pour stocker des données. Voici comment vous pouvez les utiliser :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
from typing import TypedDict 
  
class User(TypedDict): 
    name: str 
    age: int 
  
user : User = {'name': "Alice", 'age': 31} 
reveal_type(user['age'])  # revealed type is 'int'

Cependant, TypedDicts avait une limitation, où vous ne pouviez pas avoir de paramètres facultatifs dans un dictionnaire, un peu comme les paramètres par défaut dans les définitions de fonction.

Par exemple, vous pouvez le faire avec un NamedTuple :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
from typing import NamedTuple 
  
class User(NamedTuple): 
    name: str 
    age: int 
    married: bool = False 
  
marie = User(name='Marie', age=29, married=True) 
fredrick = User(name='Fredrick', age=17)  # 'married' is False by default

Cela n'était pas possible avec un TypedDict (au moins sans définir plusieurs de ces types TypedDict). Mais maintenant, vous pouvez marquer n'importe quel champ comme NotRequired, pour signaler qu'il est normal que le dictionnaire n'ait pas ce champ :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
from typing import TypedDict, NotRequired 
  
class User(TypedDict): 
    name: str 
    age: int 
    married: NotRequired[bool] 
  
marie: User = {'name': 'Marie', 'age': 29, 'married': True} 
fredrick : User = {'name': 'Fredrick', 'age': 17}  # 'married' is not required

NotRequired est plus utile lorsque la plupart des champs de votre dictionnaire sont obligatoires, avec quelques champs non obligatoires. Mais, dans le cas contraire, vous pouvez dire à TypedDict de traiter chaque champ comme non requis par défaut, puis d'utiliser Required pour marquer les champs réellement requis.

Par exemple, c'est le même que le code précédent :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
from typing import TypedDict, Required 
  
# `total=False` means all fields are not required by default 
class User(TypedDict, total=False): 
    name: Required[str] 
    age: Required[int] 
    married: bool  # now this is optional 
  
marie: User = {'name': 'Marie', 'age': 29, 'married': True} 
fredrick : User = {'name': 'Fredrick', 'age': 17}  # 'married' is not required

contextlib.chdir

contextlib a un petit ajout, qui est un gestionnaire de contexte appelé chdir. Tout ce qu'il fait est de remplacer le répertoire de travail actuel par le répertoire spécifié dans le gestionnaire de contexte et de le remettre à ce qu'il était avant lorsqu'il se ferme.

Un cas d'utilisation potentiel peut être de rediriger vers où vous écrivez les journaux :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import os 
  
def write_logs(logs): 
    with open('output.log', 'w') as file: 
        file.write(logs) 
  
  
def foo(): 
    print("Scanning files...") 
    files = os.listdir(os.curdir)  # lists files in current directory 
    logs = do_scan(files) 
  
    print("Writing logs to /tmp...") 
    with contextlib.chdir('/tmp'): 
        write_logs(logs) 
  
    print("Deleting files...") 
    files = os.listdir(os.curdir) 
    do_delete(files)

De cette façon, vous n'avez pas à vous soucier de modifier et de rétablir manuellement le répertoire actuel, le gestionnaire de contexte le fera pour vous.

Source : note de version

Et vous ?

Avez-vous déjà utilisé Python ou vous en servez-vous actuellement ? Qu'en pensez-vous ?
Quelles améliorations ou nouveauté vous intéressent le plus ?

Voir aussi :

JavaScript toujours devant Python et Java dans le dernier classement de RedMonk, tandis que Go et TypeScript gagnent des places
Le langage de programmation Rust gagne en popularité parmi les développeurs et fait son entrée dans le top 20, selon Tiobe. Python, Java, C et C++ s'accaparent à eux seuls de 55% de parts de marché

Une erreur dans cette actualité ? Signalez-nous-la !

Avatar de archqt
Membre émérite https://www.developpez.com
Le 29/10/2022 à 15:01
Le C++ a une syntaxe moche ? autant les templates à la création cela peut être effectivement compliqué, mais cela est réservé pour les cas complexes aux experts, autant pour le reste je ne trouve pas cela moche
4  0 
Avatar de HaryRoseAndMac
Membre extrêmement actif https://www.developpez.com
Le 31/10/2022 à 0:15
Citation Envoyé par archqt Voir le message
Le C++ a une syntaxe moche ? autant les templates à la création cela peut être effectivement compliqué, mais cela est réservé pour les cas complexes aux experts, autant pour le reste je ne trouve pas cela moche
De toute façon, dire qu'un langage est moche, quel qu'il soit c'est un peu débile ...
Le langage est secondaire dans tout les cas.

Il n'est là que pour permettre d'atteindre un but précis : donner vie à une idée.
Celui qui se masturbe sur le langage est clairement à des années lumières d'avoir compris le boulot de développeur.

Même si il est évident que certains sont plus adapté à des contextes et que donc, la règle numéro une dans ce métier c'est "ça dépend", même là, s'attacher à ça n'est pas se concentrer sur les bonnes choses.

Les seuls à être convaincu de l'inverse de ce que je viens d'écrire, ce sont les mecs formés à l'arrache en six mois, ultra spécialisé qui ne connaissent rien au code et qui se rendrons compte dans 5 ans qu'ils étaient sur la mauvaise route depuis le départ.
4  1 
Avatar de electroremy
Membre éprouvé https://www.developpez.com
Le 21/11/2022 à 14:38
La performance des langages n'est pas seulement accessoire

Un bon langage qui permet de faire plus facilement du code compact et rapide permet :
- d'économiser de l'énergie
- d'utiliser un système avec moins de RAM, moins de ROM et un CPU plus lent ce qui éviter de remplacer son matériel

Un langage à la fois lent et populaire est une catastrophe pour la planète et nos portemonnaies.

Bien sûr, il y a le rôle du programmeur qui doit optimiser son code.

Exemple : sur Arduino, j'ai optimisé deux bibliothèques pour faire "rentrer" le code de mon projet dans les 32ko de rom (client TCP IP + écran LCD graphique + dalle tactile + capteurs). Non seulement ça marche mais en plus mes fonctions sont à la fois plus complète et sont 8 à 13 fois plus rapide que le code d'origine.
Mais ça demandé pas mal de travail...
...et surtout mon code n'est plus "portables" sur les autres cartes à microcontrôleur
...normal, on ne peut pas tout avoir

Quand on voit ce que demande en RAM et en CPU les versions actuelles de Word et Excel, alors qu'on ne fait pas grand chose de plus avec que les versions de 1997...

Mon premier ordinateur était un Amiga 1200, CPU 68020 à 14Mhz, 2Mo de RAM, j'étais impressionné par ce qu'arrivait à en tirer les programmeurs de l'époque, notamment sur des jeux dignes de bornes d'arcade, des applications graphiques et musicales.

S'agissant de la syntaxe et du confort, ça ne dépend pas que du langage mais aussi de l'IDE.
Un langage "facile" peut être performant : si par exemple les premières versions de Visual Basic étaient lentes, la version VB.NET permet de faire du code aussi rapide qu'en C#
2  0 
Avatar de leopard78
Candidat au Club https://www.developpez.com
Le 07/11/2022 à 14:15
Si tu code moche en C++ c’est ton problème &#128556; pas les autres !
1  0 
Avatar de fred1599
Expert éminent https://www.developpez.com
Le 16/11/2022 à 8:04
Bonjour,

Dire qu'un langage est moche est très souvent subjectif et un avis de ce type ne concerne que soit. On lui demande le sien, il le donne... ce n'est pas pour ça que le contredire lui fera changer d'avis sur le C++ ou tout ceux qui sont d'accord avec lui.

La version 3.11 est sans doute améliorée, ce n'est pas pour autant que j'ai choisi ce langage, et ce n'est pas non plus pour cela que des développeurs se mettront à apprendre ce langage.

Même si c'est plus rapide, ça ne le sera pas suffisamment face à des langages compilés et autant dire que c'est souvent à cette comparaison (langages interprétés - compilés) que l'on fait référence.

Par contre cette amélioration peut être intéressante et faire la différence sur des langages comme ruby, R et surtout celui qui commence à faire de l'ombre... julia.

julia étant connu pour être bien plus performant et spécialisé pour des travaux scientifiques, on peut être amené à choisir l'un ou l'autre, et cette version 3.11 équilibre les forces côté performances.
1  0 
Avatar de shenron666
Expert confirmé https://www.developpez.com
Le 07/11/2022 à 20:51
Le binaire compilé en C++ s'exécute en seulement 1,8 fois moins de temps que le code javascript.
Mon premier avis est que je doute que le code C++ soit correctement écrit.
En plus, comparer des temps d'exécution de cet ordre (moins d'une seconde) manque de précision.

Dire que C++ a une syntaxe moche est plus que ridicule vu que la beauté c'est subjectif, et la beauté d'un code c'est... encore plus subjectif.
Perso je préfère le C# mais jamais je n'irai dire que c'est plus beau ou moins moche qu'un autre langage.
0  0 
Avatar de byrautor
Membre éclairé https://www.developpez.com
Le 08/11/2022 à 13:36
3 fois plus rapide !
Mazette, il faut y croire, ma conviction est que ...
0  0 
Avatar de vivid
Membre régulier https://www.developpez.com
Le 16/11/2022 à 7:35
X3 fois plus rapide, c'est reconnaitre que la version précédente a été conçue avec les pieds ! ils font la promotion de leur incompétence ?!!
0  0