Cours Python avec exercices

écrit par Christophe Darmangeat dans le cadre du M2 PiSE

Les bases du langage

1. Les variables

1.1 Noms et types

Les noms de variables sont sensibles à la casse. La variable toto est donc différente de la variable Toto ! Pour gérer les noms de variables composés de plusieurs mots, une pratique astucieuse est celle dite du camelcase, la « casse en chameau » : on met les initiales de chaque mot (et seulement elles) en majuscules, en commençant toutefois par une minuscule. Cela donne des noms comme : tauxEmprunt, ageRetraite, nbEnfantsMineurs, etc.

En Python, le typage est dynamique. En clair, on ne déclare pas les variables, c’est le langage lui-même qui en détermine le type lors de la première affectation. Les types disponibles sont les suivants (tableau comparatif avec l’algorithmique et le C) :

Tableau des types de variables disponibles

Algorithmique C Python
Numérique short, int, long, long, long int, float, double, long double int, long, float, complex
Alphanumérique char*, char[] str
Booléen bool bool

Nota Bene : Signalons d'emblée que python gère les variables d'une manière un peu particulière, et qui aura parfois des conséquences inattendues sur le déroulement du programme. Mais comme ce point mérite qu'on s'y arrête en détail, et que pour le moment, nous n'en sommes qu'à poser les fondations, on choisira de l'ignorer... sans oublier qu'il existe !

1.2 Conversion d’un type vers un autre

Lorsqu'on doit convertir une donnée d'un type vers un autre, deux situations peuvent se présenter :

  1. On souhaite changer un type restreint en un type vers un type plus large : par exemple, un int vers un float. Dans ces cas-là, la conversion est dite implicite (autrement dit, elle se fait toute seule). C’est assez normal : tout entier est par définition un décimal – l’inverse n’étant évidemment pas vrai – et il ne peut donc y avoir aucun problème à effectuer la conversion.

  2. En revanche, on peut souhaiter effectuer une conversion vers un type tout simplement différent (par exemple, un int vers un str), ou même depuis un type large vers un type restreint (par exemple, float vers int). Cette opération s’appelle un cast, et elle s'effectue via une fonction, qui obéit en toute logique à la syntaxe suivante : typeCiblé(valeurInitiale). Ainsi, pour récupérer dans monNombre un nombre saisi au clavier (et donc reçu sous forme de chaîne de caractères dans maSaisie), on écrira : monNombre = int(maSaisie)

Lorsque le type de départ ne correspond pas au type d’arrivée, un Cast engendrera nécessairement une erreur d'exécution. Ainsi, la conversion en numérique de "Bonjour", par exemple, n’a pas de sens ! Le plus souvent, il faudra donc mettre en place des « attrape-erreurs » pour parer à ce genre d’éventualités – nous verrons cela plus loin.

2. Les opérations

Aux opérations numériques de base s’ajoutent quelques possibilités supplémentaires :

Opérations numériques

Opérateur Opération
+addition
-soustraction
*multiplication
/division
//division entière
%modulo
**exposant

Opérations logiques (booléennes)

Opérateur Opération
==égalité
!=différence
andaddition
orsoustraction
xormultiplication
notdivision

3. Les principaux blocs d’instructions

3.1 Les entrées – sorties

Tout comme en C, l’entrée s’effectue en Python sous la forme d’une fonction : input(). Celle-ci renvoie toujours une chaîne de caractères. Pour utiliser le résultat en tant que nombre, il sera donc nécessaire de le convertir (ou de le « caster ») en int ou en float.

À noter qu’on peut envoyer en argument à la fonction input() le message que l’on veut faire afficher pour la saisie. Tout cela donnera par exemple :

age = (int)input("Entrez votre age :")

Pour la sortie, on utilise print(), qui est également une fonction. Les arguments sont en nombre variable, et séparés par des virgules.

3.2 Les tests

La syntaxe des tests obéit aux règles suivantes :

  • Un test commence par un if, suivi d’un booléen et du signe « deux points »
  • Les deux autres mots-clés  sont else: et elif:, qui correspondent à « sinon » et « sinonsi »
  • Un point essentiel : il n’existe pas d’instruction de fin de bloc. Celle-ci est marquée par l’indentation, et uniquement par elle.

Cela donne par exemple :

If age < 18:
   print("vous êtes mineur")
elif age < 65 :
   print("vous êtes majeur actif")
else:
   print("vous êtes retraité")

3.3 Les boucles

En Python, les instructions de boucles sont nombreuses. Pour commencer, il y a bien sûr l’incontournable « Tant Que… » : while, qui est suivi de la condition et des deux points, exactement comme le if. De la même manière que pour les tests, il n’existe pas d’instruction de fin de boucle : celle-ci est marquée par l’indentation.

while booléen:
   instructions

En ce qui concerne la boucle Pour, c’est un peu plus compliqué. Il en existe en réalité plusieurs formes, que l’on découvrira au fur et à mesure des outils auxquels elles s’appliquent. Pour le moment, on en restera à la plus classique, celle qui permet d’incrémenter un entier. Il s'agit de la boucle for, qui utilise obligatoirement la fonction range(). Celle-ci admet deux ou trois arguments, et renvoie une plage de valeurs. Le premier argument correspond à la valeur initiale (inclue), le seconde à la valeur finale (exclue). Le troisième argument, facultatif, désigne le pas.

Ainsi, pour aller de 0 à 9, on écrira :

for i in range(0, 10):
   instructions

Une pomme de discorde : il existe en python des instructions dites de « saut », destinées à perturber le déroulement normal des boucles : il s'agit de break et de continue. L'emploi de ces instructions divise le monde des informaticiens en deux grands camps irréconciliables. Les premiers considèrent qu'elles constituent une violation des principes de la programmation structurée, au même titre que le sinistre goto, et qu'un code propre devrait toujours s'abstenir de les employer. Les seconds avancent au contraire le fait que dans certaines circonstances, et sans réellement rompre la structure, ces instructions permettent d'éviter un code plus lourd et plus cryptique. Étant donné mon niveau de compétence, je me garderais bien d'avoir un avis tranché sur cette question. Mais à titre personnel, ayant pris le pli de ne jamais les utiliser, je continuerai à préconiser une programmation satisfaisant de manière rigoureuse (d'aucun diront psychorigide) aux standards de la programmation structurée.

3.4 Les modules (fonctions et sous-procédures)

Python ne distingue pas formellement les fonctions des sous-procédures. Les modules obéissent donc à une syntaxe unique :

Def nomModule (arguments)
   Instructions

Parmi les instructions, il peut y avoir return, suivie d’une ou plusieurs valeurs. Mais alors, direz-vous, si les fonctions et les procédures possèdent la même syntaxe, comment fait-on pour gérer le passage des arguments par valeur ou par référence ? Cette question possède une réponse simple : on ne le gère pas, et l'on considère que les arguments sont systématiquement passés par référence. En réalité, on vient ici d'ouvrir ici une véritable boîte de Pandore, celle de la manière dont sont gérées ls variables en Python, et qui mérite qu'on s'y arrête longuement... ce que nous ferons plus tard.

Ex 1 : Lapin

L'ordinateur choisit où se trouve un lapin, quelque part entre 50 et 150 mètres du chasseur (l'utilisateur). Une fois le lapin posé, le chasseur doit le tuer en annonçant la bonne distance (exclusivement en nombres entiers). À chaque tir, la machine vérifie que le chasseur a bien entré un tir convenable (entre 50 et 150) et elle lui fait recommencer la saisie dans le cas contraire. Une fois le tir enregistré, le lapin répond au chasseur « trop court », « trop long » ou « Aaaaargh, tu m'as eu ! ».

NB : il faut évidemment pour cela générer un nombre aléatoire. Je vous laisse volontairement chercher l'information pertinente sur internet et l'utiliser.

Ex 2 : Super-Lapin

Même exercice mais on intègre deux éléments supplémentaires : d'une part, le chasseur dispose de seulement 6 cartouches par partie. S'il n'arrive pas à tuer le lapin avec son barillet, il a perdu et la partie s'arrête. D'autre part, à la fin de chaque partie, on demande au joueur s'il souhaite rejouer (et si oui, naturellement, le jeu recommence !)

4. Chaînes de caractères

4.1 Généralités

Il existe trois moyens possibles de délimiter une chaîne de caractères : par des guillemets simples, doubles, ou par des triples guillemets simples (!). Soit :

toto = 'Bonjour'
toto = "Bonjour"
toto = '''Bonjour'''

4.2 Chaînes et indices

Un outil puissant est que toute chaîne peut être directement manipulée par des indices, avec de multiples possibilités consistant à utiliser, au choix, un seul, deux ou trois arguments, avec exactement les mêmes règles que la fonction range, évoquée un peu plus haut à propos de la boucle for. Rappel donc :

  1. Le premier argument est l’indice du caractère de départ, inclus et commençant à zéro.
  2. Le second argument est le caractère d’arrivée ; il définit donc une plage, de laquelle ce caractère est exclu : [3 : 7] désigne les caractères d’indice 3 à 6.
  3. Le troisième argument définit le pas (step) : tout se passe donc comme si on effectuait une boucle implicite sur la chaîne.

Si un argument est omis, il est remplacé par une valeur par défaut. Par exemple, pour la chaîne cours = "Ceci est un cours de python" :

  • cours[5] vaut e
  • cours[-1] vaut n
  • cours[5:11] vaut est un
  • cours[5:11:2] vaut etu
  • cours[-1:-6] vaut python
  • cours[:8] vaut cours[0:8] et donc Ceci est
  • cours[::-1] vaut nohtyp de sruoc nbu tse iceC

4.3 Boucles de chaîne

J'avais évoqué le fait que Python propose toute une série de boucles for en plus de la forme la plus standard (celle du compteur numérique). Une de ces formes concerne tout particulièrement les chaînes de caractère :

for c in "voici la chaîne à traiter":

Ici, c prendra successivement la valeur de tous les caractères de la chaîne.

4.4 Méthodes de chaîne

Python étant un langage objet, même les variables les plus simples en apparence sont en réalité des instances créées à partir de classes. Celles-ci disposent de méthodes (fonctions ou procédures) qui s’appliquent donc à tout objet de cette classe. En d’autres termes, dans un langage objet, une méthode est une alternative aux fonctions traditionnelles des langages procéduraux. Sur le fond, il s’agit de la même chose (un traitement qui produit un résultat grâce à diverses informations qui lui sont fournies, mais la syntaxe est différente. Là où la fonction s’écrit :

nomFonction(chaîneTraitée, arg1, arg2, etc.)

La méthode s’écrit :

chaîneTraitée.nomMéthode(arg1, arg2, etc.)

Python inclut d'innombrables méthodes pour traiter les chaînes. Sans forcément les mémoriser toutes, il n’est pas inutile d’en connaître beaucoup. Tout d’abord, parce qu’elles peuvent faire gagner un temps précieux dans le développement (on n’est pas obligé de réinventer la roue à chaque fois qu’on en a besoin !). Ensuite, parce que les autres développeurs les connaissent, et qu’il faut être capable de relire le travail d’autrui…

4.4.1 Méthodes renvoyant des booléens

Commençons par les méthodes renvoyant des booléens et qu’on pourrait, pour cette raison, appeler « informatives ». Les méthodes suivantes renvoient true si...

  • isupper() : la chaîne contient uniquement des majuscules
  • islower() : la chaîne contient uniquement des minuscules
  • istitle() : la chaîne contient uniquement des majuscules en initiales
  • isalpha() : la chaîne contient uniquement des caractères alphabétiques
  • isdigit() : la chaîne contient uniquement des chiffres
  • isspace() : la chaîne contient uniquement des espaces
  • startswith(prefix[, start[, stop]]) : la chaîne commence par prefix
  • endswith(suffix[, start[, stop]]) : la chaîne se termine par suffix

4.4.1 Méthodes retournant des chaînes :

  • lower() convertit la chaîne en minuscules
  • upper() convertit la chaîne en majuscules
  • capitalize() convertit la première lettre en majuscule
  • swapcase() intervertit la casse
  • strip([chars]) supprime les espaces (ou un autre caractère passé en argument) à gauche et à droite de la chaîne
  • lstrip([chars]) idem, uniquement à gauche
  • rstrip([chars]) idem, uniquement à droite
  • find(sub[, start[, stop]]) renvoie l'index de la chaîne sub dans la sous-chaîne allant de start à stop. Renvoie -1 si la chaîne n’est pas trouvée.
  • index() fait de même, mais produit une erreur (exception) si la chaîne n'est pas trouvée
  • replace(old, new[, count]) remplace chaque occurrence de old par new (count fois si l’argument est précisé)

Il existe encore quelques autres méthodes de chaîne très puissantes, mais qui mettent en œuvre des connaissances qui seront abordées seulemement au chapitre suivant. On ne perd rien pour attendre : c’est là qu’on les retrouvera…

Ex 3 : Dentiste

Chez le dentiste, la bouche grande ouverte, lorsqu'on essaie de parler, il ne reste que les voyelles. Même les ponctuations sont supprimées.
Écrivez une fonction dentiste qui reçoit en argument une chaîne de caractères et qui renvoie une autre chaine ne contenant que les voyelles qu'elle contient, placées dans le même ordre que dans la chaîne initiale.

Ex 4 : Balisage

Écrivez une fonction pour créer une chaîne HTML avec des balises autour du (des) mot(s). Ainsi :

  • balisage('i', 'Hello') donne <i>Hello</i>
  • balisage('b', 'Salut toi') donne <b>Salut toi</b>

Ex 5 : Bégaiement

Ecrire une fonction qui reçoit en argument un mot et qui le renvoie en doublant chaque lettre. Ainsi, begaiement("bon") a pour valeur bboonn

Ex 6 : Palindrome

Écrire une fonction palindrome qui renvoie True si le mot passé en argument est un palindrome.

Ex 7 : Anagrammes

Écrire une fonction qui renvoie True si les deux mots passés en arguments sont des anagrammes.

Ex 8 : Mini-scrabble

Écrire une fonction Scrabble qui renvoie True si les lettres du premier mot passé en arguments permettent de former le second mot (chaque lettre ne peut servir qu’une seule fois).