Explorer les profondeurs des annotations de type en Python. Partie 1

Depuis 2014, lorsque Python a introduit la prise en charge des annotations de type , les programmeurs ont travaillé sur leur implémentation dans leur code. L'auteur du document, dont nous publions aujourd'hui la première partie de la traduction, dit que, selon son évaluation, des annotations de type assez audacieuses (parfois appelées «astuces») sont utilisées dans environ 20 à 30% du code écrit en Python 3. Voici les résultats de l'enquête, qu'elle a, en mai 2019, publiée sur Twitter.

Il s'est avéré que les annotations sont utilisées par 29% des répondants. Selon l'auteur de l'article, ces dernières années, elle a de plus en plus rencontré des annotations de type dans divers livres et guides d'étude.

La deuxième partie



Dans la documentation Python, les termes «type hint» et «type annotation» sont utilisés de manière interchangeable. L'auteur de l'article utilise principalement le terme «type hint», nous utilisons le terme «type annotation».

Cet article couvrira un large éventail de problèmes concernant l'utilisation des annotations de type en Python. Si vous souhaitez discuter de l'article original avec l'auteur, vous pouvez utiliser le mécanisme de pull-request .

Présentation


Vous trouverez ici un exemple classique de l'apparence du code écrit à l'aide d'annotations de type.

Voici le code régulier:

def greeting(name):     return 'Hello ' + name 

Voici le code auquel les annotations sont ajoutées:

 def greeting(name: str) -> str:    return 'Hello ' + name 

Le modèle selon lequel le code avec des annotations de type est exécuté ressemble à ceci:

 def function(variable: input_type) -> return_type:    pass 

À première vue, il semble que l'application d'annotations de type dans le code semble simple et directe. Mais il y a encore une bonne part d'incertitude dans la communauté des développeurs pour comprendre exactement ce que sont les annotations de type. De plus, il existe même une ambiguïté sur la façon de les appeler correctement - «annotations» ou «astuces», et sur les avantages de leur utilisation dans la base de code.

Lorsque j'ai commencé à faire des recherches sur ce sujet et à réfléchir à la nécessité d'utiliser des annotations de type, je me suis senti complètement confus. En conséquence, j'ai décidé de faire la même chose que je fais toujours, après avoir rencontré quelque chose d'incompréhensible. J'ai décidé de faire une recherche approfondie sur ce problème et d'exposer mes recherches sous la forme de ce matériel, qui, je l'espère, sera utile à ceux qui, comme moi, veulent traiter des annotations de type en Python.

Comment les ordinateurs exécutent-ils nos programmes?


Afin de comprendre ce que les développeurs Python essaient de réaliser avec des annotations de type, parlons des mécanismes des systèmes informatiques qui se trouvent à plusieurs niveaux en dessous du code Python. Grâce à cela, nous pouvons mieux comprendre le fonctionnement général des ordinateurs et des langages de programmation.

Les langages de programmation, à la base, sont des outils qui vous permettent de traiter des données à l'aide d'une unité centrale de traitement (CPU), ainsi que de stocker en mémoire les données à traiter et les données résultant du traitement.


Circuit informatique simplifié

Un processeur est une chose assez stupide dans son essence. Il est capable d'effectuer des actions impressionnantes avec des données, mais il ne comprend que les instructions de la machine, qui se résument à des ensembles de signaux électriques. Le langage machine peut être représenté comme composé de zéros et de uns.
Afin de préparer ces zéros et ceux que le processeur comprend, vous devez traduire le code d'une langue de haut niveau vers une langue de bas niveau. C'est là qu'interviennent les compilateurs et les interprètes.

Si le langage est compilé ou exécutable (le code Python est exécuté au moyen de l'interpréteur), alors le code dans ce langage se transforme en code machine de bas niveau qui contient des instructions pour les composants informatiques de bas niveau, c'est-à-dire pour le matériel.

Il existe plusieurs façons de traduire du code écrit dans un langage de programmation en code que les machines peuvent comprendre. Vous pouvez soit créer un fichier avec le code du programme et le convertir en code machine à l'aide du compilateur (c'est ainsi que fonctionnent C ++, Go, Rust et d'autres langages), soit exécuter le code directement à l'aide de l'interpréteur, qui sera chargé de convertir le code en commandes machine. C'est ainsi que, avec l'aide d'interprètes, des programmes en Python sont lancés, ainsi que dans d'autres langages de "scripting", comme PHP et Ruby.


Schéma de traitement de code de langue interprété

Comment le matériel sait-il comment stocker des zéros et des uns représentant les données avec lesquelles le programme fonctionne en mémoire? Notre programme doit indiquer à l'ordinateur comment allouer de la mémoire à ces données. Et quelles sont ces données? Cela dépend des types de données pris en charge par une langue particulière.

Les types de données sont disponibles dans toutes les langues. En règle générale, les types de données sont l'un des premiers sujets que les débutants apprennent à apprendre la programmation dans un certain langage.

Il existe par exemple d'excellents tutoriels sur le même Python - c'est ici que vous pouvez trouver des informations détaillées sur les types de données. En termes simples, les types de données sont différentes façons de représenter les données stockées en mémoire.

Parmi les types de données existants, par exemple, des chaînes et des entiers peuvent être notés. L'ensemble des types de données disponibles pour le développeur dépend du langage de programmation qu'ils utilisent. Voici, par exemple, une liste des types de données Python de base :

 int, float, complex str bytes tuple frozenset bool array bytearray list set dict 

Il existe des types de données composés d'autres types de données. Par exemple, une liste en Python peut stocker des entiers ou des chaînes, ainsi que les deux.

Afin de savoir combien de mémoire vous devez allouer pour stocker certaines données, l'ordinateur doit savoir quel type de données le programme va mettre en mémoire. Python a une fonction getsizeof intégrée qui nous permettra de connaître la quantité de mémoire, exprimée en octets, nécessaire pour stocker les valeurs de divers types de données.

Voici une excellente réponse à StackOverflow où vous pouvez trouver des informations sur la façon de trouver les tailles des valeurs «minimales» qui peuvent être stockées dans différents types de variables.

 import sys import decimal import operator d = {"int": 0,    "float": 0.0,    "dict": dict(),    "set": set(),    "tuple": tuple(),    "list": list(),    "str": "a",    "unicode": u"a",    "decimal": decimal.Decimal(0),    "object": object(), } #   ,        d_size = {} for k, v in sorted(d.items()):    d_size[k]=sys.getsizeof(v) sorted_x = sorted(d_size.items(), key=lambda kv: kv[1]) sorted_x [('object', 16), ('float', 24), ('int', 24), ('tuple', 48), ('str', 50), ('unicode', 50), ('list', 64), ('decimal', 104), ('set', 224), ('dict', 240)] 

Par conséquent, en triant un dictionnaire contenant des échantillons de valeurs de différents types, nous pouvons découvrir que la taille maximale est un dictionnaire vide ( dict ) et suivi d'un ensemble ( set ). En comparaison avec eux, très peu d'espace est nécessaire pour stocker un entier (type int ).

L'exemple ci-dessus nous donne une idée de la quantité de mémoire requise pour stocker les différentes valeurs utilisées dans les programmes.

Pourquoi cela devrait-il nous déranger? Le fait est que certains types sont meilleurs que d'autres pour résoudre certains problèmes, ce qui vous permet de résoudre ces problèmes plus efficacement. Dans certaines situations, les types doivent être soigneusement vérifiés. Par exemple, il est parfois vérifié que les types de données utilisés dans le programme ne vont pas à l'encontre de certaines hypothèses formulées lors de la conception du programme.

Mais quels sont ces types? Pourquoi en avons-nous besoin? C'est là que le concept de «système de type» entre en jeu.

Introduction aux systèmes de types


Il y a longtemps , dans une galaxie lointaine et éloignée, les gens qui effectuaient des calculs mathématiques manuellement se rendaient compte que s'ils comparaient les «types» avec des nombres ou des éléments d'équations, ils pouvaient réduire le nombre d'erreurs logiques qui apparaissent lors de la dérivation des preuves mathématiques de ces éléments.

Étant donné qu'au tout début l'informatique se réduisait essentiellement à l'exécution de grands volumes de calculs manuels, certains de ces anciens principes ont été transférés à ces calculs. Les systèmes de types sont devenus un outil utilisé pour réduire le nombre d'erreurs dans les programmes en affectant des types appropriés à diverses variables ou éléments.

Voici quelques exemples:

  • Si nous écrivons un logiciel pour la banque, nous ne pouvons pas utiliser les lignes du fragment de code qui calcule le solde du compte de quelqu'un d'autre.
  • Si nous travaillons avec les données d'une enquête et que nous voulons comprendre si quelqu'un a répondu positivement ou négativement à une question, alors les réponses «oui» et «non» seront le plus naturellement encodées en utilisant un type logique.
  • Lors du développement d'un grand moteur de recherche, nous devons limiter le nombre de caractères que les utilisateurs de ce système peuvent entrer dans le champ de requête de recherche. Cela signifie que nous devons vérifier la conformité de certaines données de chaîne avec certains paramètres.

Aujourd'hui, en programmation, il existe deux principaux types de systèmes. Voici ce que Steve Klabnik écrit à ce sujet: «Un système de type statique est le mécanisme par lequel le compilateur vérifie le code source et attribue des étiquettes (appelées« types ») aux fragments de programme, puis les utilise pour tirer des conclusions sur le comportement du programme. Un système de type dynamique est le mécanisme par lequel le compilateur génère du code pour surveiller quels types de données (qui, par coïncidence, sont également appelés "types") sont utilisés par le programme. "

Qu'est-ce que cela signifie? Cela signifie que lorsque vous travaillez avec des langages compilés, vous devez généralement affecter à l'avance des types d'entité. Grâce à cela, le compilateur pourra les vérifier lors de la compilation du code et savoir s'il sera possible de créer un programme significatif à partir du code source qui lui est fourni.

J'ai récemment rencontré une explication de la différence entre le typage statique et dynamique. C'est probablement le meilleur texte que j'ai lu à ce sujet. En voici un fragment: «J'avais l'habitude d'utiliser des langages typés statiquement, mais au cours des dernières années, j'ai principalement programmé en Python. Au début, l'utilisation de la frappe statique m'a un peu ennuyé. Il y avait un sentiment que la nécessité de déclarer des types de variables ralentit et m'oblige à trop exprimer mes idées. Python m'a juste laissé faire ce que je voulais, même si j'ai accidentellement fait quelque chose de mal. Utiliser des langues avec une frappe statique, c'est comme confier une tâche à quelqu'un qui demande toujours à nouveau, clarifier les petits détails du dossier qu'il est chargé de terminer. Le typage dynamique est lorsque la personne à qui la tâche est confiée acquiesce toujours. Dans ce cas, il y a un sentiment qu'il vous a compris. Mais parfois, il n'y a aucune certitude absolue que celui à qui la tâche est confiée a correctement compris ce qu'on attend de lui. »

En parlant de systèmes de types, je suis tombé sur quelque chose que je n'ai pas compris immédiatement. À savoir, les concepts de «typage statique» et de «typage dynamique» sont étroitement liés aux concepts de «langage compilé» et de «langage interprété», mais les termes «statique» et «compilé», ainsi que les termes «dynamique» et «interprété» ne sont pas des synonymes. . Le langage peut être typé dynamiquement, comme Python, et en même temps compilé. De même, un langage peut être typé statiquement, comme Java, mais également interprété (par exemple, dans le cas de Java, lors de l'utilisation de Java REPL).

Comparaison des types de données dans des langages typés statiquement et dynamiquement


Quelle est la différence entre les types de données dans les langues à typage statique et dynamique?

Lorsque vous utilisez la saisie statique, les types doivent être déclarés à l'avance. Par exemple, si vous travaillez en Java, vos programmes ressembleront à ceci:

 public class CreatingVariables {  public static void main(String[] args) {    int x, y, age, height;    double seconds, rainfall;    x = 10;    y = 400;    age = 39;    height = 63;    seconds = 4.71;    rainfall = 23;    double rate = calculateRainfallRate(seconds, rainfall);   } private static double calculateRainfallRate(double seconds, double rainfall) {  return rainfall/seconds; } 

Faites attention au début du programme. Plusieurs variables y sont déclarées, à côté desquelles se trouvent des indications sur les types de ces variables:

 int x, y, age, height; double seconds, rainfall; 

De plus, les types sont spécifiés à la fois lors de la déclaration de fonctions et de la déclaration de leurs arguments. Sans ces déclarations de type, le programme ne peut pas être compilé. Lors de la création de programmes Java, dès le début, vous devez planifier les types de ces entités. Par conséquent, le compilateur, tout en traitant le code de ces programmes, saura exactement ce dont il a besoin pour vérifier le processus de génération du code machine.

Python élimine les tracas d'un programmeur. Un code Python similaire pourrait ressembler à ceci:

 y = 400 age = 39 height = 63 seconds = 4.71 rainfall = 23 rate = calculateRainfall(seconds, rainfall) def calculateRainfall(seconds, rainfall):  return rainfall/seconds 

Comment tout cela fonctionne-t-il dans les entrailles de Python? À suivre ...

Chers lecteurs! Quel langage de programmation que vous avez utilisé a laissé l'impression la plus agréable?

Source: https://habr.com/ru/post/fr463929/


All Articles