Plus loin avec Python
Introduction
Le langage Python possède une bibliothèque standard bien fournie qui permet d’alléger et de simplifier le code sur les traitements des types de base, des types complexes, les procédures, etc.
Mais les interpréteurs Python poussent le concept plus loin et vont jusqu’à intégrer une grande variété de bibliothèques supplémentaires. Une telle intégration dans le langage de base permet alors d’effectuer le déploiement d’une application bien plus rapidement et fait aussi disparaître les risques d’incompatibilités entre le langage et une de ces bibliothèques.
Ces bibliothèques natives permettent de répondre aux besoins les plus courants d’un programme dont les interactions avec l’extérieur se multiplient (réseau, fichiers, interface utilisateur, etc.).
Nous allons aborder, dans ce chapitre, l’utilisation de quelques-unes des bibliothèques les plus fréquemment utilisées.
XML
1. Présentation
Aussi bien utilisé en tant que support pour des protocoles de communication que pour le stockage de données, le langage XML est omniprésent dans l’informatique moderne. Il offre des avantages nombreux et indiscutables qui en font un format très populaire (pérennité, interopérabilité, hiérarchisation des données, établissement d’une grammaire, etc.). Il est très probable qu’un développeur, Python ou autre, se retrouve tôt ou tard à manipuler des fichiers XML dans une application.
Il existe deux principales méthodes pour traiter les fichiers XML :
-
Mettre complètement en mémoire le fichier XML cible. Une fois en mémoire, les données, généralement représentées par une structure d’arbre, peuvent être parcourues librement en utilisant des méthodes adéquates. Cette technique de traitement des fichiers XML est appelée DOM (Document Object Model). DOM implique une utilisation mémoire proportionnelle à la taille du fichier XML puisque celui-ci est entièrement lu et chargé. Cela permet de modifier facilement et directement une partie précise d’un fichier XML, mais en cas de fichiers d’une trop grande taille, l’occupation mémoire en limitera l’utilisation.
-
Lire en flux continu le fichier sans rien stocker et effectuer les traitements au fur et à mesure de cette lecture. Cette méthode peut ne pas être adaptée si jamais on a besoin de parcourir le fichier XML de façon non linéaire. Cette méthode est appelée SAX (Simple API for XML). Ne stockant pas le fichier en mémoire, elle permet de lire des flux XML de toutes tailles, mais au prix de traitements plus complexes en cas de modification d’un segment du fichier.
2. DOM
a. Lecture
Les interpréteurs Python disposent d’une implémentation de parseur DOM appelée minidom. Celle-ci permet de mettre en œuvre très rapidement la lecture d’un fichier XML.
Prenons un exemple de mise en œuvre de ce module avec la lecture du contenu XML suivant :
<Voiture nom='delorean'>
<Proprietaire>Emmett Brown</Proprietaire>
<Equipements>...
JSON
Le JSON (JavaScript Object Notation) est un format d’échange de données assez minimaliste, qui s’inspire, comme son nom l’indique, de la façon dont les objets sont représentés en JavaScript :
var voiture = {
modèle : "Delorean",
propriétaire : "Emmett Brown",
équipements : [{ équipement : { type : "Convecteur temporel" } },
{ équipement : { type : "Générateur à fusion" } }]
}
Le JSON, bien que possédant une puissance d’expression moindre, est extrêmement utile afin de transmettre des informations « simples » telles que chaînes de caractères, entiers, tableaux, etc. Choisir ce format peut être encore plus judicieux s’il doit être lu par un site web écrit ou utilisant du JavaScript, car la transformation de ces données en un objet JavaScript est quasiment instantanée, puisqu’utilisant la même notation qu’un objet déclaré par un développeur. Tandis qu’en XML, il faut parser et transformer les données, ce qui nécessite davantage...
IHM
1. Tkinter
Il existe en Python un très large choix de bibliothèques pour développer des applications avec interfaces graphiques. En effet, les outils de création d’IHM les plus connus proposent une adaptation de leur code pour une utilisation en Python. Présente par défaut dans presque toutes les installations Python, la bibliothèque Tkinter est assez minimaliste et dispose d’un rendu graphique plutôt austère étant donné ce qui se fait aujourd’hui.
a. Création d’une fenêtre
Commençons simplement par la création d’une fenêtre graphique vide pour une application se basant sur une IHM.
Le point de départ sera bien sûr l’importation du module Tkinter. Le composant graphique (ou widget) qui peut en contenir d’autres est appelé frame. C’est donc une frame qu’il faut instancier afin d’obtenir une fenêtre graphique :
from tkinter import Frame
ma_fenetre = Frame()
# Lancement de la boucle principale de l'IHM.
ma_fenetre.mainloop()
Pour un résultat des plus épuré :

L’appel de la boucle principale de l’IHM est un appel bloquant, c’est-à-dire que la prochaine ligne de code ne sera pas exécutée tant que la fenêtre ne sera pas close. Ce blocage permet à Tkinter de prendre la main sur l’exécution du processus pour donner à l’application son caractère événementiel et attendre que quelque chose se produise pour effectuer un traitement (un clic sur la croix de fermeture de la fenêtre par exemple).
Il est temps de personnaliser davantage cette fenêtre. Afin de mieux contrôler les aspects de la fenêtre principale de l’application, la création d’une classe héritant de Frame s’impose. En effet, plutôt que de changer les attributs de la frame, autant modifier ceux-ci directement dans son constructeur. L’avantage est que, si jamais il faut instancier une deuxième fenêtre (pour afficher les options du logiciel par exemple), celle-ci aura déjà les mêmes attributs que la première, ce qui rend l’IHM plus homogène et donc moins perturbante pour l’utilisateur.
from tkinter import Frame
...
Bases de données
1. Présentation
Une base de données est un logiciel permettant de stocker, manipuler et rechercher des informations de façon optimisée et intelligente. Stocker des informations dans un fichier XML peut être suffisant dès lors qu’il s’agit d’une petite quantité de données. Cependant, la recherche dans un fichier peut s’avérer inefficace, que ce soit en matière de temps de traitement (parcours de l’arbre via SAX) ou d’espace mémoire (stocker l’arbre entier comme en DOM). De plus, une grande quantité de données stockées en format textuel sur un disque dur peut prendre une place considérable, et le fait de les compresser implique qu’à chaque accès, il faut lancer une décompression, ce qui demande encore du temps et utilise plus de mémoire.
Le but d’une base de données est justement de régler au mieux tous ces problèmes de stockage, d’utilisation mémoire (mémoire vive ou disque dur), d’optimisation de la recherche, etc. La configuration d’une base de données permet de donner plus d’importance à telle ou telle contrainte. Par exemple, si la réactivité d’une application est primordiale, il faudra configurer la base afin qu’elle optimise au maximum les accès, ce qui nécessitera certainement plus d’espace mémoire pour stocker davantage d’informations afin d’accélérer la recherche. Si, au contraire, le logiciel doit tourner sur un espace disque minuscule, alors la compression doit être à son maximum, sachant que cela aura un impact négatif sur les temps de réponse.
Il existe de nombreux paradigmes de bases de données. Celui qui se rapproche le plus de la POO est la base de données « relationnelle ». Un peu à la manière d’un diagramme de classes, les informations sont regroupées en « tables » reliées entre elles par des liens. Ces tables peuvent être assimilées à des classes, où chaque colonne est un attribut, et où chaque ligne est une instance. Le code suivant produit des données qui pourraient être stockées dans une table...
Multithreading
1. Présentation
Un thread, ou littéralement un « fil » (d’exécution), est une unité de traitement au sein d’un processus. Un processus peut contenir plusieurs threads, qui s’exécutent alors en parallèle. La différence majeure entre un ensemble de threads et un ensemble de processus est que les processus ont chacun leur zone mémoire propre, tandis que les threads d’un même processus partagent une mémoire commune.
Il n’est pas rare que la résolution d’un problème de programmation passe par une solution basée sur le concept de programmation concurrente. Dans les faits, un logiciel interagit avec quantité d’éléments et réagit à quantité d’événements qui peuvent se produire en même temps. Par exemple, un clic de souris doit pouvoir être capté par un programme, mais celui-ci doit dans le même moment écouter une interface réseau dans l’attente d’un message, tout en affichant une vidéo et en jouant la piste sonore. Mettre en place un paradigme de programmation pouvant résoudre le traitement en parallèle de différentes tâches est donc bien plus logique et efficace. En effet, les enchaîner les unes à la suite des autres comporte des risques évidents de dégradation de la réactivité de tous ces traitements (vidéo qui saccade, interface peu réactive, etc.).
La pratique la plus courante pour traiter plusieurs tâches dans un langage procédural est de les traiter successivement les unes à la suite des autres. Cette approche n’est cependant pas la plus élégante dans la mesure où elle contraint de régler séquentiellement des problématiques qui peuvent survenir simultanément.
Prenons l’exemple d’une voiture à laquelle on doit faire prendre un virage, c’est-à-dire que l’on doit la faire rouler tout en la faisant tourner. L’approche séquentielle va forcer à exécuter en boucle la tâche « rouler » puis à la stopper afin d’exécuter la tâche « tourner », et ce, jusqu’à ce que le virage...
Développement web
1. Présentation
Aujourd’hui, Internet fait partie intégrante de nos vies, et par conséquent, le développement d’applications fonctionnant à travers le Web est devenu une compétence recherchée. Pour simplifier, une application web consiste en deux parties :
-
Le « front-end », qui est la partie « frontale » de l’application, c’est-à-dire celle qui est manipulée directement par l’utilisateur. Les technologies front-end sont généralement HMTL, JavaScript, React, etc. Cette partie est généralement l’apanage du navigateur web.
-
Le « back-end », qui est le « moteur » de l’application. C’est cette partie qui effectue les traitements lourds, comme le stockage d’informations en base de données, les calculs longs à réaliser, les différents traitements nécessaires au fonctionnement de l’application. Des exemples de langages typiquement back-end sont PHP ou ASP.NET.
Une des difficultés de ce genre de développement réside dans la communication entre toutes les couches impliquées :
-
L’utilisateur tape une URL dans la barre de son navigateur.
-
Une requête pour recevoir la page à afficher est envoyée à un serveur via Internet.
-
Lequel serveur réceptionne et décode cette requête, puis met en marche des algorithmes de génération de page.
-
Ces traitements ont de grandes chances d’aller chercher des informations dans une base de données.
-
Il faut ensuite intégrer ces données dans la génération de la page afin d’offrir à l’utilisateur des informations personnalisées (nom, prénom, panier en cours, etc.).
-
Une fois la page générée, il faut la retourner à celui qui l’avait demandée en premier lieu.
Navigateur, couches réseau, serveur, programme, base de données... toutes ces entités sont indépendantes et, par conséquent, doivent avoir un moyen de communiquer les unes avec les autres. L’un des problèmes auxquels font face les applications web est justement ces interfaces de communication, par lesquelles circulent des données...