Programmation en langage Python
RETOUR
Quand on utilise les notebooks Jupyter au sein d'une distribution Anaconda 3, on commence par apprendre à détecter la version de Python en cours d'utilisation. Voici le contenu d'un premier notebook avec son code: [détecter_la_version].
Il existe un certain nombre d'usages courants à respecter dans l'édition de script en Python. Dans le notebook suivant [usage_courant], on regarde comment casser une ligne trop grande, comment écrire plusieurs instructions à la suite selon l'esprit Python, comment écrire des commentaires et comment respecter l'indentation dans les blocs.
Mots réservés et fonctions internes
Dans le langage Python, il y a des instructions qui permettent d'exécuter du code. Ces instructions sont des mots réservés qui ne peuvent pas être utilisés pour déclarer des variables [mots_réservés]. Python possède un ensemble de fonctions internes dites aussi fonctions intégrées [fonctions_internes]. Python est un langage orienté objet c'est-à-dire que toutes les données sont des objets. Chaque classe qui représente un type d'objet possède des attributs. Parmi ces attributs, il y a des fonctions que l'on appelle des méthodes [méthodes_internes]. Il y a quatre sortes d'opérations en Python : les opérations numériques, les affectations-opérations, les comparaisons et les appels ou accès à items. Derrière chaque opérateur se cache une méthode dite méthode spéciale [méthodes_spéciales]. Le langage Python est un langage typé dynamiquement, les variables ne sont pas typées à l'avance, leur type est défini en fonction de la valeur qu'elles contiennent [type_fonction_methode].
Données et types de données
Chaque donnée (objet) traitée par Python possède un type. Pour connaître le type de xx, on exécute l'instruction type(xx). De plus, Python prévoit un affichage pour toute donnée, quel que soit son type. L'appel print(xx) transforme xx en une chaîne str(xx) et affiche cette dernière [types_importants]. On peut tester le type d'une donnée avec la fonction type() [tester_les_types]. Python est un langage à typage dynamique (duck typing) et non pas un langage à typage statique (static typing) [typage_dynamique].
Affectations, identificateurs et aliasing
La manière classique d'affecter une donnée à une variable est de spécifier le nom de la variable, puis d'autoriser l'affectation d'une valeur par un signe égal (=), enfin de spécifier la valeur affectée à la variable [maniere_affectation]. Chaque opérateur d'arité 2 possède une version permettant l'opération demandée suivie d'une affectation [opération_simultanée]. En Python, un identificateur pointe toujours vers une donnée et jamais vers un autre identificateur [notion_identificateur]. La fonction id() donne l'adresse mémoire (memory address) de chaque donnée connue [fonction_id]. Une variable est globale si elle est définie dans le programme principal (à la racine en quelque sorte). Une variable est locale si elle est définie dans une fonction. Une variable est interne si elle est définie dans le module builtins [résolution_identificateur].
Modules et bibliothèques
Python possède des modules, composés de bibliothèques et de librairies, permettant d'enrichir le langage. En plus de ces modules, on trouve sur le web des centaines de modules gratuits à télécharger et à installer sur son propre système. Dans un module, on trouve des fonctions, des constantes, des classes (types), etc. Il existe toutes sortes de modules : des modules pour faire des mathématiques, des modules pour faire des sciences, des modules pour créer des environnements graphiques, etc. On trouve la liste complète des modules de base (y compris ceux présents sur tout système par défaut) sur le site officiel de Python à la page https://docs.python.org/3/library. La directive import permet d'importer un module par l'écriture import nom_module. Une fois le module importé, les objets qui y sont contenus sont considérés par Python comme des attributs de ce dernier [importer_module]. On peut importer une fonction issue d'un module, en utilisant le nom du module ou bien un alias [contenu_module].
Affichage de texte
Pour afficher une donnée, on utilise la fonction print() en lui passant un certain nombre d'arguments. Après l'affichage demandé par la fonction print(), Python va à la ligne [affichage_texte]. L'instruction print(xx) déclenche implicitement une conversion de xx en chaîne de caractères. Cette conversion implicite se fait avec la fonction str(). C'est donc la chaîne str(xx) qui est affichée [fonction_str_repr].
Calculs arithmétiques
Dans Python, les calculs numériques se font avec les types int (nombre entier), float (nombre à virgule) et complex (nombre complexe) [types_nombres]. Les opérations fondamentales et élémentaires sont l'addition (opérateur +), la soustraction (opérateur -), la multiplication (opérateur *), la division (opérateur /), la division entière (opérateur //), le reste entier (opérateur %) et l'exposant (opérateur **) [operations_elementaires]. Python effectue les opérations sur les entiers de type int de manière exacte. Il n'y a aucune limitation dans la taille des entiers, si ce n'est que de très grosses tailles peuvent ralentir le système ou bien poser des problèmes de mémoire [remarque_int_float]. Comme tous les langages, Python travaille en binaire. Par conséquent, il est incapable d'encoder de manière exacte les nombres à virgule dont l'écriture binaire est illimitée : par exemple, c'est le cas du nombre 0.1 dont la représentation binaire est répétitive à savoir 0.00011001100110011... (constitution de la représentation binaire répétitive 0011) [dysfonctionnement_float]. Nous décrivons ici les fonctions internes, pour une utilisation courante dans le calcul arithmétique, qui sont abs, int, round, divmod, pow, fl oat, sum, eval, complex, min, max et range [principale_fonction]. Différents préfixes permettent d'écrire un nombre entier en binaire, en hexadécimal et en octal [calcul_binaire_hexa_octal]. En informatique, NaN signifie not a number. En Python, NaN ou nan ne sont pas des mots réservés, mais il connaît la notion de NaN [nan_nombre_infini]. Les modules math et cmath apporte la gestion des fonctions mathématiques usuelles comme pour la trigonométrie, etc [module_math_cmath]. Le module random permet d'imiter le hasard en générant des quantités pseudo-aléatoires [module_random].
La saisie au clavier
La fonction input() permet la saisie de données au clavier. Lorsque Python exécute un programme et tombe sur une instruction input(), il s'arrête et attend que l'utilisateur effectue une saisie au clavier. Python ne reprend l'exécution que lorsque l'utilisateur appuie sur la touche ENTREE. La fonction retourne alors ce qui a été saisi sous la forme d'une chaîne de caractères [saisie_clavier].
La structure IF - ELIF - ELSE
La structure if simple est une structure dans laquelle si la condition v_condition vaut True, alors le bloc est exécuté. L'instruction if est une instruction composée, ce qui veut dire qu'elle est suivie d'un caractère deux-points puis d'un bloc d'instructions qui est forcément indenté [structure_if_elif_else].
La boucle FOR
Une boucle for est une boucle pour effectuer le code se trouvant à l'intérieur (boucle de répétitions). Elle s'utilise toujours avec un itérable [boucle_for].
La boucle WHILE
La boucle while a un fonctionnement classique de boucle standard. Elle représente l'équivalent du "tant que" en algorithmique [boucle_while].
La gestion des erreurs
La plupart du temps, une exception est une erreur survenue lors de l'exécution d'une instruction dans un programme. Nous verrons plus en détail qu'en fait c'est un peu plus compliqué. L'instruction try permet de traiter les exceptions. La structure try-except est la structure de base pour lever des exceptions consécutivement au déclenchement d'une erreur détectée [gestion_erreur]. Quand Python lève une exception, l'exécution s'arrête et une description du problème rencontré est affichée en rouge dans le shell [base_exception_classe]. Pour traiter une erreur en particulier, l'instruction except peut être suivie du nom d'une exception [erreur_particulier]. Normalement Python lève une exception lorsque celle-ci a vraiment eu lieu, mais on peut l'obliger à lever une exception qui n'a pas eu lieu en fonction d'un contexte de programmation spécifique. Pour cela on utilise une instruction raise [exception_raise]. Le mot réservé assert oblige Python à tester l'assertion proposée et à déclencher une exception AssertionError si celle-ci est fausse. On peut s'en servir pour traiter des erreurs ou des états indésirés [assertion].
Les fonctions
La syntaxe pour définir une fonction est simple. On utilise le mot-clé def suivi par le nom de la fonction, puis une parenthèse ouvrante suivie d'une parenthèse fermante et on termine par un caractère deux-points [definition_fonction]. Quand on a une fonction qui demande trois arguments, appeler cette fonction consiste à lui passer obligatoirement trois arguments. Ne pas passer la quantité des arguments demandés déclenche une erreur [argument_fonction]. Il est conseillé d'ajouter une description à chaque fonction, composant ainsi une documentation. De cette façon, on peut informer l'utilisateur sur ce que fait la fonction, sur ce qu'elle a besoin comme paramètre et sur ce qu'elle retourne comme données [documentation]. En Python, on peut définir une fonction gt() à l'intérieur d'une fonction ft() [fonction_dans_fonction]. Une fonction Python peut posséder des arguments facultatifs, à condition de leur donner une valeur par défaut [valeur_argument_defaut]. Nous avons déjà eu l'occasion de décrire la décompression (unpacking) avec l'opérateur splat (caractère *) [decompresser_iterable_etoile]. Avec un dictionnaire, on peut se servir de la décompression à la source dans la définition d'une fonction [decompresser_dictionnaire]. On a déjà vu au cours d'une précédente fiche que la fonction print() possède des arguments nommés qui modifie l'affichage [argument_nom_obligatoire]. Le mot réservé lambda permet de fabriquer une fonction à la volée et de l'affecter si on le souhaite à une variable [fonction_lambda].
Décorateurs de fonctions
Un décorateur permet de se soustraire à un objet pour en modifier le comportement. Le principe de la décoration en Python est d’appliquer un décorateur à une fonction, afin de retourner un nouvel objet (généralement une fonction). On peut donc voir le décorateur comme une fonction prenant une fonction en paramètre et retournant une nouvelle fonction [decorateur].
Plage d'entiers
Le type range définit une plage d'entiers. Mathématiquement, il s'agit d'une suite arithmétique d'entiers qui s'arrête à un certain rang [plage_entier].
Le type booléen
En mathématiques, un booléen ne peut prendre que deux valeurs : vrai ou faux. Python encode les booléens avec le type bool [type_booleen].
Les chaînes de caractères
Un objet de type str est une séquence non mutable. C'est donc un conteneur, un itérable, un objet indexable et découpable en tranche (sliceable) [chaine_caractere]. La fonction repr() retourne la représentation littérale de tout objet sous forme de chaîne de caractères [representation_chaine]. Pour lister les attributs du type str, on utilise la fonction dir() comme à l'habitude [methode_str].
Formater les chaînes
La méthode format() transforme des données en str selon des spécifications choisies et les insère dans une chaîne (un patron) aux endroits désirés [formatage_bloc].
Stocker des objets dans une liste
Le type liste est une séquence modifiable de type list. Un élément d'une liste peut être de n'importe quel type [type_liste]. On peut simuler une matrice avec une liste de listes [simuler_matrice]. Il est très courant en mathématiques de définir des ensembles en compréhension. La constitution de liste en compréhension se fait assez simplement [comprehension]. Quand on dispose d'une liste de listes, on peut récupérer tous les items de toutes les listes à l'intérieur de la liste en une seule instruction [complement_liste]. Comme d'habitude, on peut lister tous les attributs du type list avec la fonction dir() [exploration].
Les uplets de type tuple
Un tuple est une séquence non mutable (non modifiable) de type tuple. On peut délimiter un tuple avec des parenthèses (même si on peut presque toujours s'en passer). Les items d'un tuple peuvent être de n'importe quel type [type_tuple].
Les générateurs
On commence par un exemple introductif qui consiste à composer la suite des carrés pour n allant de 0 à 9 [generateur]. Le module itertools est le module intégré qui nous permet de gérer les itérateurs de manière efficace. Ils permettent de parcourir très facilement les itérables comme les listes et les chaînes [itertools].
Les ensembles
Une structure de type set est un ensemble au sens mathématique du terme. Un type set est un conteneur donc un itérable. Un ensemble n'est pas une séquence (les éléments ne sont pas indexés). Les délimiteurs du type set sont les accolades { } [ensemble].
Les dictionnaires
La structure qui définit un dictionnaire est une structure très présente dans les différents langages de programmation (Perl, Java, C++, C#, etc). Dans le langage Python, un dictionnaire est représenté par le type dict [dictionnaire].
Les chaînes d'octets
Les types bytes et bytearray sont utiles pour lire des fichiers plus compliqués qu'un simple fichier texte au format .txt. Sur la plupart des machines informatique, le byte mesure 8 bits, autrement dit le byte est synonyme d'octet [chaine_octet].
Le module os
Le module os propose des outils pour gérer plus facilement les fichiers. Le répertoire courant (current work directory que l'on abrège par cwd) est le répertoire par défaut dans lequel Python va chercher ou enregistrer des fichiers [module_os].
Lire et écrire des fichiers
Toute lecture et écriture de fichier se fait au travers d'un objet fichier. Un objet fichier est un objet qui pointe vers un fichier positionné à un emplacement physique [fichier_usuel]. Un objet fichier binaire est un objet pointant vers un fichier quelconque avec lequel les échanges se font en mode binaire [fichier_binaire]. Le module pickle permet d'enregistrer n'importe quel type de donnée dans un fichier : bool, int, float, complex, str, bytes, list, etc [module_pickle]. Nous avons décrit les instructions try-except-else-finally dans une précédente fiche. Ces commandes sont précieuses pour la lecture et l'écriture de fichiers. En effet, nous ne sommes jamais à l'abri d'un problème quand on travaille avec ce type d'objets [complement].
Encodage et décodage
Lorsqu'un système informatique sauve du texte sous forme de fichier, il commence par encoder le texte, c'est-à-dire il remplace chaque caractère par un byte (éventuellement plusieurs) selon une norme d'encodage bien précise. C'est la chaîne de bytes ainsi obtenue qui est finalement sauvegardée [encodage_decodage].
Introspection chez Python
La fonction type() retourne le type de n'importe quel objet [introspection_type]. Python est un langage orienté objet. Toute donnée traitée par Python est un objet. Tout objet appartient à une classe (une classe est un type). Les objets et les classes possèdent des attributs. Il y a deux sortes d'attributs : les attributs qui sont des données et les méthodes [fonction_attribut]. L'appel isinstance(mon_objet,ma_classe) renvoie True si mon_objet est de classe ma_classe. L'appel issubclass(x,y) renvoie True si x est une classe fille de y [fonction_classe]. La fonction dir() retourne la liste des attributs (en particulier les méthodes) de n'importe quel objet [complement].
Programmation orientée objet
Une classe est la définition d'un concept métier, elle contient des attributs (des valeurs) et des méthodes (des fonctions) [classe_instance]. Le constructeur de classe compose l'objet en fonction des attributs de classe [constructeur]. Les attributs d'instance ont une vie qui est liée à l'instance à laquelle ils sont rattachés. Un attribut d'instance n'existe qu'à travers l'instance qui lui est liée. Ainsi, si l'instance est détruite, l'attribut d'instance l'est également [attribut_instance]. Le pendant du constructeur, qui est la méthode appelée lors de l'instanciation d'une classe, est le destructeur, qui est la méthode appelée lorsque l'instance est détruite [destructeur]. L'héritage est le mécanisme par lequel une classe possède les membres d'une autre classe, afin d'éventuellement les spécialiser ou d'en ajouter de nouveaux [heritage]. Le polymorphisme est un terme désignant les mécanismes où l'on manipule des objets de différents types en tant qu'objets d'un seul et unique type [polymorphisme]. L'encapsulation est une manière de définir une classe de telle sorte que ses attributs ne puisse pas être directement manipulés depuis l'extérieur, mais seulement indirectement par l'intermédiaire de ses méthodes [encapsulation]. Les énumérations sont le meilleur moyen de représenter un ensemble fini d'éléments, comme les jours de la semaine ou les couleurs de l'arc-en-ciel [enumeration].
Lecture et écriture XML
LXML est un puissant module permettant de manipuler des données XML. Il est basé sur d'autres technologies réputées et a pour objectif d'en donner un équivalent pythonique. LXML est très riche, tellement riche qu'on ne sait parfois pas par quel bout le prendre [module_lxml].
HAUT