Blog ENI : Toute la veille numérique !
💥 Un livre PAPIER acheté
= La version EN LIGNE offerte pendant 1 an !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Scripting Python sous Linux
  3. Le langage Python
Extrait - Scripting Python sous Linux Développez vos outils système (2e édition)
Extraits du livre
Scripting Python sous Linux Développez vos outils système (2e édition)
2 avis
Revenir à la page d'achat du livre

Le langage Python

Introduction

Maintenant que les types de données n’ont plus de secret, il est temps de détailler un peu plus le langage Python en lui-même.

La fonction print()

La première fonction que l’on va étudier c’est, évidemment, la fonction print().

Depuis la version 3 de Python c’est une fonction, avant, c’était une instruction et donc il n’y avait pas besoin de parenthèses.

Tout d’abord, print(), par défaut, affiche l’objet demandé puis envoie une fin de ligne (Line Feed).

Ce comportement peut être modifié par l’option end, qui permet de spécifier ce que l’on veut à la fin.

>>> for x in [1,2,3]: 
...   print(x , end="-") 
... 
1-2-3->>> # pas fin de ligne … des '-' à la place 

print() peut aussi afficher plusieurs valeurs d’un seul coup.

>>> print(1,2,3) 
1 2 3 

print() permet de modifier le séparateur dans ce cas.

>>> print(1,2,3, sep="/") 
1/2/3 

Mais surtout, print() permet de formater les données de deux manières :

En premier est venu le formatage C-STYLE, comme le ferait printf() en langage C ou la commande printf du shell.

Exemple

>>> print( "[ %10s ]" % "hello") 
[      hello ] 

Ensuite vient le formatage avec la commande format(), ce qui permet de générer des documents de manière simple et élégante.

>>> print( "[ {} le {} ]".format( "bonjour", "monde" )) 
[ bonjour le monde ] 

1. Print() formatage C-STYLE

Cette méthode de formatage a bien failli disparaître du langage Python, mais de gros modules comme le module ’logging’ l’utilisent encore et de nouveaux types de données, comme la classe ’bytes’, vont finalement l’utiliser.

"<chaîne avec formatage>" % valeur  
ou 
"<chaîne avec de multiples formatages>" % (valeur, valeur, ... ) 

Et comme beaucoup, nous trouvons que c’est assez simple à taper, de plus certaines habitudes sont difficiles à oublier.

L’expression du format :

  • Le caractère ’ %’ indique le début du format

  • Une option facultative (# 0 <espace> - +)

  • Une clé (facultative) entourée de parenthèses (nom_de_champ)

  • Une indication de longueur minimale (facultative)...

Les structures conditionnelles

Depuis la version 3.10, on peut utiliser deux structures conditionnelles en python : l’inévitable if-elif-else et le couple match-case.

1. La structure conditionnelle if-elif-else

La première structure if-elif-else est, comme le reste du langage, simple :

if <condition> : 
   <bloc de code> 

Si condition est vraie, alors on exécute le bloc de code.

elif est une contraction de else if et on peut parler de "bloc de test" comme on parle de bloc de code.

Un bloc de test commence par une instruction if, peut être accompagné d’une ou plusieurs instructions elif, et éventuellement d’une instruction else à la fin.

Dans une succession de if .. elif .. elif, les conditions sont évaluées les unes après les autres jusqu’à ce qu’une de ces conditions soit vraie, et, dans ce cas, on exécute le bloc de code associé et on sort du "bloc de test".

Si aucune condition n’est vraie et qu’une instruction else est présente, alors on exécute le bloc de code associé à cette instruction else.

Sinon, on sort du bloc de code.

if <condition1> : 
   <bloc de code 1> 
elif <condition2> : 
   <bloc de code 2> 
elif <condition3> : 
   <bloc de code 3> 
... 
else : 
   <bloc de code else> 

Bien entendu, il est possible d’imbriquer le tout.

if <condition1> : 
   if <condition1.1> : 
       <bloc de code1.1> 
   else : 
       <bloc de code else> 
elif <condition2> : 
   <bloc de code 2> 
else : 
   <bloc de code else> 

Dans cet exemple, l’indentation comme syntaxe prend toute son importance.

2. La structure conditionnelle match-case

Avant la version 3.10 de Python, il y a quelques années, l’absence de structure conditionnelle style switch-case en Python a alimenté les discussions sur les réseaux sociaux et forums spécialisés.

Pourquoi Python, ce langage si évolué, n’a-t-il pas, comme ses camarades de jeu (perl, ruby, C...), une structure conditionnelle...

Les boucles

Il y a deux manières de faire des boucles en Python : les boucles ’for’ et les boucles ’while’.

Comme d’habitude, on commence par le plus simple.

L’instruction while a comme syntaxe :

while <condition> : 
   <bloc de code> 

Tant que la condition est vraie, on boucle sur le bloc de code.

L’instruction for se base sur une liste de valeurs et une variable contenant la valeur courante.

for <variables> in <liste de valeurs> : 
   <bloc de code> 

Tant que l’on peut alimenter la variable avec la liste de valeurs, on exécute le bloc de code.

La liste de valeurs derrière l’instruction in peut être tout objet permettant que l’on parcoure ses valeurs, ce que l’on nomme un itérable.

<variables> est au pluriel, ce n’est pas une faute de frappe, la raison sera dévoilée dans quelques pages.

Parmi les types de données itérables en Python, on trouve les chaînes de caractères, les listes, les dictionnaires, les tuples et les sets.

1. Quelques exemples simples

# fichier : loop0.py 
 
# Boucle while 
compteur = 1 
 
while compteur <= 10: 
   print("Compteur : %s " % compteur) 
   compteur += 1 
 
 
# Boucle for 
for n in [1,2,3]: 
   print(n)  

 

## Exemple en mode interactif 
 
>>> for c in "abcd": 
...   print(c) 
... 
a 
b 
c 
d 

2. La fonction range()

Peut-être l’avez-vous remarqué, Python ne propose pas de boucle avec des compteurs intégrés. Pour cela, il faut utiliser la fonction range().

range( [début,] fin [, pas]]) génère un objet itérable qui commence à "début", se termine à "fin" avec un incrément de "pas".

L’argument début est optionnel ; par défaut, cela commence à zéro.

L’incrément pas est optionnel et est par défaut à 1.

Exemple

>>> for x in range(0,5): 
...   print(x) 
... 
0 
1 
2 
3 
4 
>>> for x in range(1,10,2): 
...   print(x) 
... 
1 
3 
5 
7 
9 

Maintenant...

Les fonctions

Évidemment, le langage Python permet de créer ses propres fonctions.

Cela permet de factoriser le code et de diviser un algorithme complexe en sous-ensembles plus simples.

Comme pour le reste, une fonction se définit simplement avec l’instruction ’def’ de la manière suivante :

def <nom de la fonction>(arguments) : 
   <bloc de code> 

Les noms de fonctions sont soumis aux mêmes règles que pour les variables (pas de mots réservés, pas de chiffre au début…), et, par convention, commencent par une minuscule.

Les noms en Python commençant par une majuscule désignent généralement une classe (String, Float…), mais, là aussi, il s’agit d’une convention.

Une fois la fonction définie, elle fait partie de l’arsenal standard et peut être utilisée comme les fonctions natives de Python (print(), len(), max()…).

Exemple

>>> def dis_bonjour(): 
...   return "Bonjour" 
... 
>>> dis_bonjour() 
'Bonjour' 

Détail important : les parenthèses. Elles sont nécessaires pour distinguer une variable d’une fonction.

Dans l’exemple précédent, la fonction retourne une valeur, mais ce n’est pas obligatoire.

Si la fonction n’utilise pas l’instruction return, alors il s’agit d’une procédure, et dans ce cas elle retourne la valeur None.

>>> def f1():               # une fonction 
...   return "Bonjour" 
... 
>>> def p1():               #  une fonction sans 'return' 
...   print("BONJOUR")      #  = une procédure pour les puristes 
... 
 
>>> a = p1() 
BONJOUR 
>>> print(a) 
None 
 
>>> a = f1() 
>>> print(a) 
Bonjour 

Pouvoir créer des fonctions c’est bien, tout langage digne de ce nom doit permettre de le faire.

Mais encore faut-il pouvoir transmettre des paramètres à ces fonctions et là... Python a de quoi surprendre...

Les modules et les paquets

L’interpréteur Python c’est bien au début, mais maintenant les limites avec cet outil devraient être atteintes.

Il y a de plus en plus de fichiers de scripts Python dans votre répertoire et, inévitablement, ils deviennent de plus en plus longs.

De plus, à force de pratiquer ce fabuleux langage, certaines fonctions reviennent de manière récurrente dans vos scripts.

C’est le moment de commencer à structurer votre code, à le séparer en plusieurs fichiers, et donc à créer des modules ; et quand il y aura plein de modules, il sera possible de les structurer par paquets.

C’est comme cela que la librairie standard python, ou "stdlib", est structurée ; celle-ci sera étudiée dans le chapitre Librairie standard et quelques autres qui lui est consacrée.

Un module est un fichier dans lequel on trouve des définitions de variables et de fonctions que l’on peut appeler avec l’instruction import.

Un premier module :

# fichier : paquets/module1.py 
## 
## Module 1 
## 
 
M1_VAR = 10                     # une variable 
 
def M1_f1(): 
   print("Module 1 : f1")       # une fonction 

Le fichier créé, il est possible d’importer ce module de deux manières :

import <module> 

ou

from <module> import <* | objet du module> 

La première syntaxe, import nom_du_module, lit le fichier nom_du_module.py et interprète tout le code présent dans le fichier.

Ainsi, les objets contenus dans le module sont créés dans le contexte d’exécution.

Pour appeler ces objets, vous devez les préfixer par le nom du module.

Exemple avec le fichier module1.py

>>> import module1 
>>> print( module1.M1_VAR ) 
10 
>>> module1.M1_f1()    # appel de la fonction 
Module 1 : f1          # résultat 

De la même manière que :

>>> import random 
>>> random.random() 
0.9565541682756001 

La deuxième syntaxe, from <module>...

Les exceptions et la gestion des erreurs

Dans cette partie, un point important du langage Python est abordé : la gestion des erreurs et exceptions.

Il est courant de jauger la qualité d’un programme non pas sur le fait qu’il ne plante jamais, mais plutôt sur le nombre d’erreurs ou d’exceptions qu’il est capable de gérer.

Tout d’abord, il faut distinguer les erreurs de syntaxe des exceptions.

Les erreurs de syntaxe sont détectées lors de l’analyse du code : oubli du ’ :’, erreur de frappe sur une instruction…

Les exceptions n’arrivent que lors de l’exécution du script ; la syntaxe est correcte et n’est pas en cause, mais le script exécute quelque chose d’impossible, comme la division par zéro, utilise une variable qui n’existe pas ou un mélange de types de données.

Ces exceptions sont toutes définies dans le langage Python :

ZeroDivisionError

pour la division par zéro

NameError

pour les variables inexistantes

TypeError

pour les exceptions liées aux types

Il en existe beaucoup d’autres, que l’on trouve dans la documentation officielle en ligne du langage Python sur https://docs.python.org/fr/3 (pour la version 3 de Python traduite en français).

1. Les instructions try … except … finally

Les instructions pour sécuriser un bloc de code sont try et except,avec la syntaxe suivante :

try : 
   <bloc de code à sécuriser> 
except : 
   <bloc de code en cas d'exception> 

Le bloc de code compris entre try et le premier except est exécuté.

Si aucune exception n’intervient, alors on passe à la suite après le bloc de gestion d’erreur.

En cas d’exception, l’exécution du "bloc de code à sécuriser" est interrompue et le "bloc de code en cas d’exception", après except, est exécuté.

Dans cette syntaxe, toutes les exceptions sont prises en compte.

Mais il est possible d’être plus précis et de spécifier des blocs de code par exceptions. ...

Les entrées/sorties (fichier et autres)

Jusqu’à présent, les instructions Python étudiées n’interféraient que peu avec le monde extérieur.

Maintenant, il est temps de voir ce que le langage Python propose pour les entrées /sorties, et plus précisément les fichiers.

Rien de spécialement nouveau, il suffit d’ouvrir le fichier avec l’instruction open() afin de récupérer un objet particulier : un descripteur de fichier.

Cet objet comprend plusieurs méthodes pour lire, lire des lignes, se déplacer dans le fichier et écrire.

Un exemple simple pour commencer :

#fichier : fichier1.py 
 
fichier = "data.txt"           # le nom du fichier 
 
fd = open(fichier)             # ouverture 
 
for l in fd:                   # lecture ligne à ligne 
   print("l=%s" % l, end='')   # utilisation des données 
 
fd.close()                     # fermeture 

Le fichier data.txt contient quelques lignes de texte.

Comme ceci :

Ligne 1 du fichier 
Ligne 2 du fichier 
Ligne 3 du fichier 
Ligne 4 du fichier 
Ligne 5 du fichier 

D’ailleurs, pour le générer, l’exemple suivant peut être utile :

#fichier : fichier2.py 
 
fichier = "data.txt" 
 
fd = open(fichier, "w")                     # ouverture en 
                                            # mode écriture 
 
for n in range(1, 6): 
   f.write("Ligne No %s du fichier\n" % n)  # écriture 
 
f.close()                                   #...

L’instruction With

Parcourir un descripteur de fichier avec une boucle ’for’ est déjà une manière simple et efficace de faire les choses, ou plutôt une manière pythonesque de faire les choses.

Mais Python peut faire mieux, avec l’instruction with.

La syntaxe est toujours dans la même ligne :

with <expression> [as variable] : 
   <bloc de code> 

expression doit retourner un objet compatible avec le protocole de ’Gestionnaire de contexte’ (celui-ci sera étudié plus tard).

Mais si l’on s’en tient aux grandes lignes, il est possible de l’utiliser de la manière suivante :

# exemple avec l'ouverture d'un fichier (cas typique) 
with open(fichier) as f: 
   <bloc de code> 

À la fin du bloc de code, le fichier sera fermé et la variable f, qui représente le descripteur du fichier, sera éliminée.

Voici une manière très pythonesque de lire les champs du célèbre fichier /etc/passwd :

#fichier :  lecture_password2.py 
 
with open('/etc/passwd') as f: 
   for l in f: 
       user, pswd, id_u, id_g, com, home, shell = l.split(':') 
       print( "USER    = %s" % user ) 
       print(...

Exemple de script : hdump

Maintenant, étudions un petit exemple : l’affichage en hexadécimal de n’importe quel fichier ; une version simple de la commande système hd ou hexdump.

Il y a une notion en avance de phase sur la variable sys.argv : celle-ci contient les arguments de la ligne de commandes quand on lance le script.

Exemple

python hdump.py nom_de_fichier 

Dans ce cas, sys.argv est une liste qui contient :

sys.argv[0]

=> hdump.py

le nom du script

sys.argv[1]

=> nom_de_fichier

le premier argument de la ligne de commandes

Maintenant que le principe de base est connu, il est facile de vérifier que si le nombre d’occurrences de la liste sys.argv, soit len(sys.argv), est égal à 2, alors on a bien quelque chose en argument et on peut continuer.

Deuxième notion un peu en avance : os.path.exists() est une fonction du module ’os.path’ qui renvoie True si le fichier existe.

Le script en lui-même est structuré de la manière suivante :

  • Import de module et initialisation.

  • Fonction usage(), dont le rôle est d’afficher l’usage de la commande.

  • Fonction hdump(), qui va découper en tranches le fichier et l’afficher.

  • Programme principal qui s’occupe de quelques vérifications :

  • s’il y a au moins un argument

  • si l’argument est un nom de fichier qui existe

    alors on lance la fonction hdump, avec en argument le nom du fichier ;

    sinon, on lance la fonction usage().

La fonction principale hdump() n’est pas très complexe : il s’agit d’une boucle while dont la sortie est contrôlée par la variable EOF.

Avant de démarrer la boucle, on effectue quelques initialisations et, surtout, on ouvre le fichier en mode lecture binaire.

Après, il s’agit de la répétition des séquences suivantes :

  • Lecture d’un nombre d’octets égal à la variable BUFFER et affectation à la variable record, qui devient donc une liste de ’bytes’...

Résumé

Ce chapitre est important car il permet de découvrir les principales instructions du langage Python. Il en reste encore quelques-unes, et notamment l’instruction class, qui ouvre la porte de la programmation orientée objet (POO).

Depuis le début, il vous est dit qu’avec Python tout est objet, c’est maintenant le moment de voir réellement de quoi il s’agit.