Python, un langage de programmation sûr et bien équipé !

13 Novembre 2019
AUSY - Langage de Programmation Python
Un langage sûr ...

Ci-dessous quelques exemples d’erreurs typiques de programmation en langages C/C++. Tous ces programmes compilent et ont un résultat imprévisible à l’exécution.

Il va de soi qu’aucun de ces déboires ne peuvent se produire en Python :

Erreurs de programmation en C et C++
  • Pas de pointeur en Python
  • Impossible de déclarer une variable sans l’initialiser (de manière standard)
  • Un débordement sur un tableau provoque une erreur « propre » comme illustré ci-dessous :

a={1:1}

a[2] →

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

KeyError: 2

Article Python AUSY

Même si le compilateur standard gcc de C/C++ a beaucoup amélioré les choses, avec les compilateurs d’il y a plusieurs dizaines d’années de telles erreurs pouvaient faire redémarrer l’ordinateur (expérience vécue par l’auteur).

 

Un langage pleinement "orienté objet"

Les paradigmes

Prosaïquement, un « paradigme de programmation » est une manière de formuler le problème à résoudre. En voici les principaux :

  • La programmation impérative décrit les opérations en séquence pour changer l’état du programme (Cobol, Basic, Pascal, C, Ada).
  • La programmation objet modélise le monde par des classes qui illustrent des concepts, et des objets « instances » des classes qui possèdent leurs données internes et sont modifiées par des méthodes (Java, Ruby).
  • La programmation déclarative : les composants logiciels sont indépendants du contexte et n’ont pas d’état interne :
    • La programmation fonctionnelle : chaque instruction est une équation mathématique et toute donnée d’état ou modifiable est évitée (Haskell).
    • La programmation logique (Prolog cf. « Que se cache-t-il derrière Python »).
  • La programmation événementielle (bibliothèque QT, interfaces graphiques en général, mais pas pour des langages dits « généralistes »).

Python implémente tous ces paradigmes (sauf le dernier). L’aspect objet mérite un petit approfondissement.

 

Objet, héritage (et polymorphie)

class Dog:

    def __init__(self, name):

        self.name = name

    def speak(self):

        print("ouaf")

 

mydog=Dog("medor")

 

Ce petit programme Python définit l’objet chien. La fonction __init_() est souvent abusivement appelée constructeur de l’objet (par analogie aux autres langages) mais il s’agit en fait d’un initiateur.

La classe Dog possède une méthode « speak » et un attribut « name ». Ce sont des notions élémentaires d’objet (en Python ou pas).

L’héritage, en objet, est la propriété d’une classe à spécialiser une autre classe.

class Animal:

    def speak(self):

        assert False, "Not implemented"

 

class Dog(Animal):

    # Cette notation signifie que Dog hérite de Animal

    # Même code que précédemment

Un chien est maintenant une « spécialisation » d’un animal. Un chien est un animal particulier, mais un animal quand même. La classe Dog hérite de la classe Animal. Un « Dog » est juste un « Animal » particulier. On ne peut faire parler un animal si on ne connaît pas son type (en fait sa classe), d’où l’erreur forcée au niveau de la classe Animal. La classe Dog « spécialise » la méthode « speak » de la classe Animal, on parle donc de polymorphisme.

Petite parenthèse : l’instruction « assert » qui n’est pas l’apanage de Python est un « must have » pour tout langage de programmation sérieux. Elle permet d’arrêter le programme si une condition n’est pas remplie et facilite grandement la détection et correction d’erreurs de programmation.

Nous pouvons maintenant définir une autre classe :  les animaux familiers. Notre script devient donc :

class Animal:

    def speak(self):

        assert False, "Not implemented"

 

class Dog(Animal):

    def speak(self):

        print("ouaf")

 

class Pet:

    def visit_vet(self):

        print(f"{self.name} is happy to visit the vet")

 

class PetDog(Dog, Pet):

    def __init__(self, name):

        self.name = name

 

mydog=PetDog("Medor")

 

Notre Médor est à la fois un animal, un chien et un animal de compagnie. Les instances de la classe « PetDog » héritent directement de la classe « Pet » et de la classe « Dog » et indirectement de la classe « Animal ».

Cette possibilité de réaliser un héritage multiple distingue Python de son concurrent Java. En effet Java n’implémente, pour des raisons de simplicité, que l’héritage simple. Le langage C++ propose également l’héritage multiple mais de manière dangereuse pour un développeur non averti (problème du diamant que nous ne détaillerons pas ici).

 

Un langage fourni avec les batteries...

Définition

Cette expression signifie que le langage est fourni avec tout un tas de librairies un nombre de librairies conséquent qui permettent de réaliser des choses intéressantes très rapidement et très facilement.

On trouve en premier lieu les librairies standards auxquelles on accède avec juste cette instruction :

import enum

à placer en début de fichier, pour pouvoir accéder aux fonctions et aux objets dans son programme.

Il serait très fastidieux de lister ici la librairie standard qui contient environ une centaine d’éléments, aussi le rédacteur de ces lignes se limitera aux plus pertinentes qu'il a réellement utilisées.

Passons sur les extensions « naturelles » du langage:

  • "enum" pour les types énumérés,
  • "copy" pour des copies d'objets (copie profonde ou superficielle),
  • "datetime" pour la datation,
  • "time" pour le temps – typiquement une attente passive d’une seconde : time.sleep(1)
  • "random" pour une génération aléatoire (hors utilisation en cryptographie).

Par ailleurs les modules « collections » et « itertools » ont déjà été évoqués en début d'article. (cf « Que se cache-t-il derrière Python »).

Voici les modules que l'on retrouve dans les applications classiques en Python qui permettent de bénéficier d'un système puissant et pratique. Ce sont des tâches que tout programmeur rencontre plusieurs fois dans son activité. Nous les avons illustrées avec un exemple le plus simple possible.

 

Le log

Le module « logging » sert à logguer des messages (erreur critique, erreur, avertissement, information, mise au point).

 

Fichier example_logging.py:

import logging

 

logging.basicConfig(format = '%(asctime)s  %(levelname)-10s %(processName)s  %(name)s %(message)s', filename = "my.log")

 

logging.warning("Le petit est sans surveillance")

logging.error("Le petit joue avec les allumettes")

logging.critical("La maison brule")

 

Contenu du fichier my.log après execution :

2018-06-12 08:46:22,942  WARNING    MainProcess  root Le petit est sans surveillance

2018-06-12 08:46:22,942  ERROR      MainProcess  root Le petit joue avec les allumettes

2018-06-12 08:46:22,942  CRITICAL   MainProcess  root La maison brule

 

L’analyse des arguments

Le module « argparse » sert à analyser les arguments du programme : paramètres avec valeurs, avec informations ou pas, exclusifs ou pas etc.

 

Fichier example_args.py:

import argparse

parser = argparse.ArgumentParser()

parser.add_argument("--verbose", help="augmenter la verbosité",

                    action="store_true")

args = parser.parse_args()

if args.verbose:

    print("Je raconte ma vie")

 

Exécutions:

$ python3 example_args.py -h

usage: example_args.py [-h] [--verbose]

 

$ python3 example_args.py

 

$ python3 example_args.py --verbose

 

python3 example_args.py

Je raconte ma vie

 

Fichier de configuration

Le module « configparser » permet d’analyser le contenu d'un fichier texte de paramétrage de l'application avec des paragraphes et des attributs couple valeur.

 

Fichier config.ini:

[Jérémie]

favorite_language = Python

 

Fichier example_config.py:

import configparser

 

config = configparser.ConfigParser()

config.read('config.ini')

favorite = config.get('Jérémie', 'favorite_language')

print(f"Favorite = {favorite}")

 

Exécution:

python3 example_config.py

Favorite = Python

 

Sauvegarde et restauration … trop facile !

Le module « pickle » permet de sauvegarder toute structure simple ou complexe de données dans un fichier et la restaurer ultérieurement. Cette opération pourrait coûter de nombreuses heures de développement et de mise au point dans un autre langage.

 

Fichier example_pickle_save.py:

import pickle

test_list = ['egg', 'ham', 'spam']

with open('test_pickle.pkl', 'wb') as pickle_out: 

    pickle.dump(test_list, pickle_out)

print(f"Saved : {test_list}")

 

Fichier example_pickle_load.py:

import pickle

with open('test_pickle.pkl', 'rb') as pickle_in: 

    unpickled_list = pickle.load(pickle_in)

print(f"Loaded : {unpickled_list}")

 

Exécution:

python3 example_pickle_save.py

Saved : ['egg', 'ham', 'spam']

 

python3 example_pickle_load.py

Loaded : ['egg', 'ham', 'spam']

 

Ces quatre modules apportent un immense confort de développement.

 

Librairies externes

On trouve donc en deuxième les librairies externes qui sont pléthores. Elles sont recensées sur le site du Python Package Index (« Pypi »). Elles s'installent en général par une petite commande :

pip3 install <bibliothèque>

A ce jour, le site Pypi annonce environ 170 000 projets.

Notamment (utilisés par l’auteur) :

« pillow » pour réaliser des conversion d'images

« pyQT » pour construire une interface graphique

« matplotlib » pour afficher une courbe d'évolution dans un système de fiche de version

« psutil » pour avoir des informations en temps réel sur la charge du système

« beautiful soup » pour capturer du contenu sur un groupe de diffusion sur internet

When all else fails.

Python est un langage pour lequel il existe une forte communauté prête à répondre aux questions techniques. Le site « stackoverflow » (non spécifiquement lié à Python) est le meilleur endroit pour poser une question en dernier ressort.

 

Exemple de goodies en Python …

A des fins d’illustration, nous allons volontairement nous limiter à deux fonctionnalités très importantes et agréables du langage.

 

Le format des affichages texte

Pour écrire des informations à l’écran, plusieurs méthodes se sont succédées (nous ne parlerons pas des différences entre Python 2 et Python 3).

Exemple de goodies en Python - AUSY

 

Les listes de compréhension

Les listes de compréhension, avec l’indentation, sont un peu la marque de fabrique de Python. Cela consiste à créer une séquence (une liste, un ensemble, un tuple, un dictionnaire – les types de bases en Python) en une seule instruction.

Les listes de compréhension en Python - AUSY

A noter : Guido Van Rossum (le créateur de Python) préconise d’utiliser les listes de compréhension. Attention toutefois à ne pas composer des formules trop complexes !

 

Photo Jérémie Lefrançois, consultant en Python - AUSY
Jérémie Lefrançois, consultant AUSY depuis 2004, a écrit ses premiers programmes en Basic sur ZX Spectrum en 1982. Diplômé d'un DESS en Informatique en 1989, il a touché à de nombreux langages informatiques à titre personnel ou professionnel. Il aime effectivement explorer et comparer les possibilités des différents langages et plus spécifiquement approfondir Python qui a sa prédilection depuis 2014. C'est donc avec un grand intérêt qu'il surveille les évolutions de ce langage dynamique dont il apprécie la facilité de mise en œuvre.

 

 

Aussi n’hésitez pas à visiter notre offre Big Data.

Parlons ensemble de vos projets.

contactez-nous