Corrigé du TP n o2 - Algorithmique et Python
Transcription
Corrigé du TP n o2 - Algorithmique et Python
Mathématiques supérieures le 28 Septembre 2016 o Corrigé du TP n 2 - Algorithmique et Python Dans ce TP, nous allons voir les bases de l’algorithmie via le langage Python. Nous allons apprendre à utiliser les concepts de fonctions, de structures conditionnelles et de structures itératives (les boucles). Mais tout d’abord, nous allons commencer par quelques conseils d’utilisation puis nous allons voir comment doit se présenter, se structurer un bloc d’instructions en Python. 1. Utilisation de l’éditeur Comme nous l’avons vu dans le premier TP, l’environnement de développement est essentiellement composé de deux parties : le shell que nous avons beaucoup utilisé précédemment et l’éditeur. Ce dernier a une fonction très simple : il va nous servir à enregistrer nos futurs programmes, codes, etc... En effet, comme vous pouvez le constater, tout ce que nous avez pu écrire au précédent TP dans la console interactive (shell) a totalement disparu ! Le shell ne ”sert” qu’à exécuter nos instructions mais pas à les sauvegarder. Ce n’est évidemment pas très pratique si on veut créer un script ou un logiciel. Ainsi, pour pouvoir récupérer nos codes pour de futures utilisations, nous allons utiliser l’éditeur. Celui-ci est un simple éditeur de texte : on écrit ce que l’on veut puis on enregistre notre fichier sur le disque dur. Dans l’environnement Pyzo/IEP, l’éditeur a également plusieurs fonctions supplémentaires accessibles via la barre des menus de la fenêtre de Pyzo/IEP, via des raccourcis claviers ou via le menu contextuel du clic droit de la souris (dans l’éditeur). Voyons quelques possibilités importantes sur un exemple : Écrivons tout le code suivant dans l’éditeur. Dans l’éditeur 1 2 3 4 # addition de variables L=2 M=3 print(M,'plus',L,'=',M+L) Comme on peut le voir, l’écriture de ces lignes dans l’éditeur n’a pas d’effet sur la console ! Mais alors comment demander à la console de d’exécuter cette suite d’instructions ? Et bien on utilise les commandes suivantes, au choix : Remarque : Attention, il est possible que votre éditeur soit en anglais et que le français ne soit pas disponible ; traduisez alors ”run” ou ”Execute” par ”exécuter”. Exécuter les lignes sélectionnées Exécuter tout le fichier en cours Menu ”Exécuter” ”Exécuter sélection” ”Exécuter fichier” Raccourcis claviers Alt+Entrée ou F9 Ctrl+E ou F5 Menu contextuel ”Exécuter sélection” Il y a bien-sûr d’autres options mais nous ne nous en servirons pas pour le moment. Dès à présent, testons les différentes options ci-dessus sur le code que nous avons écrit dans l’éditeur. Pour le futur, il est vivement conseillé de connaître les raccourcis claviers pour l’exécution d’instructions écrites dans l’éditeur ! Ils apportent un confort et un gain de temps appréciables ! Concernant le fichier de sauvegarde du code en lui-même ; prenons quelques petites habitudes d’organisation pour aujourd’hui et les prochains TP : 1 — Dès le début de l’édition d’un fichier dans l’éditeur on indiquera en commentaire (grâce au #), sur la première ligne, une courte description de ce que contiendra le fichier ; — Dès le début de l’édition d’un fichier, on enregistrera le fichier sur le disque dur en lui donnant un nom explicite à propos de ce qu’il contiendra. De plus, on sauvegardera très, très régulièrement le fichier en cours : il est toujours possible que survienne une panne, peu importe laquelle. Il serait dommage de perdre une, voire deux heures d’écriture de programmes ! — Pendant l’écriture du code, on commentera (toujours grâce au #) les instructions délicates à comprendre. Ainsi, notre code sera compréhensible pour d’autres et même pour soi-même si on revient plus tard lire le fichier. On restera toujours clair et concis dans nos commentaires ; pas la peine d’écrire un roman, quelques mots bien choisis suffisent. 2. Structuration du code Dans la plupart des langages informatiques, la programmation se fait par blocs d’instructions qui dépendent d’une structure de contrôle (une fonction, une boucle, une structure conditionnelle... nous allons voir tout cela, pas d’inquiétude !). Ainsi, le développeur soucieux de bien présenter son code (afin qu’il soit lisible et plus facilement compréhensible) va mettre séparer les différents blocs de son code. Ce principe à un nom : l’indentation du code. Il s’agit de décaler, indenter, chaque bloc d’un nombre d’espaces fixe grâce à la touche Tabulation. Pour la plupart des langages, l’indentation du code est une simple règle ”de bonne conduite” : ce n’est pas nécessaire, mais cela rend le code beaucoup plus lisible. Mais en Python, l’indentation est OBLIGATOIRE ! Elle fait partie de la syntaxe du langage. Ainsi, peu importe qui développe en Python, son code est toujours un minimum lisible ! Voici le principe de l’indentation en Python : Un bloc est défini par : — un en-tête qui se termine toujours par un double point (: ) — une suite d’instructions indentées par rapport à l’en-tête — le retour à l’indentation de l’en-tête (s’il y a encore des instructions ensuite). Voici quelques exemples pour mieux comprendre : Un bloc 1 entete: 2 instruction 1 3 instruction 2 4 instruction 3 Deux blocs imbriqués 1 entete1: 2 instruction 1.1 3 instruction 1.2 4 entete2: 5 instruction 2.1 6 instruction 2.2 7 instruction 1.3 8 instruction 1.4 2 Nous allons passer immédiatement à la pratique en découvrant les concepts de fonctions, de structures conditionnelles, et de boucles. Voyons tout d’abord les fonctions. 3. Définir une fonction en Python a. Définition d’une fonction Nous avons déjà manipulé quelques fonctions en Python. Par exemple, la fonction print qui a pour effet d’exécuter l’instruction qu’elle a en argument et de l’afficher dans le shell ; ou la fonction len qui retourne la longueur d’une chaîne de caractères. Mais comment faire pour créer nos propres fonctions ?? En Python, on utilise : — le mot clé def suivi du nom que l’on veut donner à notre fonction, puis suivi, entre parenthèses, de la liste de ses arguments (ou paramètres), et terminé par le double point. Voici pour l’en-tête du bloc qui défini notre fonction. — Ensuite, on indente chaque instruction composant notre fonction. Avant d’écrire la première instruction, la première ligne du bloc doit être un commentaire appelé docstring qui explique ce que fait la fonction, et la nature de chaque argument Voici un prototype de fonction en Python : Une fonction en Python 1 def nomdelafonction(arg1,arg2,arg3): 2 instruction 1 3 instruction 2 4 . 5 . 6 . Pour que la fonction renvoie un résultat après son appel, on utilisera l’instruction Testons ce concept sur un exemple. On écrit le code suivant dans l’éditeur : return. 1 def bonjour(prenom): 2 """ Fonction qui renvoie la chaîne de caractères 'Bonjour prenom ! Comment vas-tu ?' où l'argument prenom est une chaîne de caractères""" 3 resultat='Bonjour ' 4 resultat+=prenom 5 resultat+=' ! Comment vas-tu ?' 6 return resultat Ensuite, on exécute ces lignes de code (avec la méthode de notre choix : raccourcis clavier, menu,...). La fonction que l’on vient de définir a pour nom bonjour et pour argument prenom. On remarque qu’il est bien précisé dans le docstring que l’argument prenom doit être une chaîne de caractères ! Cette fonction renvoie (ou retourne) la chaîne de caractères contenue dans la variable resultat dont la valeur est obtenue par la suite d’instructions du bloc de bonjour. Ainsi, en changeant la valeur de l’argument prenom, on obtient un résultat différent. On peut comparer cela à une fonction mathématiques : Si je considère le fonction f : x 7→ 2x ; on a f (0) = 0 et f (2) = 4 ! D’accord, mais comment fait-on pour appeler notre fonction et lui donner les arguments que l’on veut ?? 3 Très simple, il suffit de l’appeler par son nom et de lui donner, entre parenthèses, le ou les arguments nécessaires. Essayons avec notre fonction bonjour. On peut essayer le code suivant, soit directement dans le shell, soit dans l’éditeur, puis en l’exécutant : mais dans ce cas, attention, il ne faut pas oublier d’enlever l’indentation relative à la fonction que l’on vient d’écrire. En effet, si on écrit notre instruction avec la même indentation que le bloc de la fonction, Python interprétera cela comme la suite de ce même bloc et pas comme une instruction séparée !! 1 bonjour('Charles') Bien-sûr, on peut essayer avec d’autres chaînes que 'Charles' 1 bonjour('Jean') Remarque 1. Pour bien comprendre ce que l’on fait, le bloc interne de la fonction bonjour comporte quatre instructions. Mais on aurait pu réduire ceci à une seule instruction, et sans même définir une variable ! 1 def bonjour(prenom): 2 """ Fonction qui renvoie la chaîne de caractères 'Bonjour prenom ! Comment vas-tu ?' où l'argument prenom est une chaîne de caractères""" 3 return 'Bonjour '+prenom+' ! Comment vas-tu ?' Exercice 1. Définir une fonction reponse qui prend pour argument une chaîne de caractère nom et qui renvoie la chaîne de caractère 'Très bien ! Et vous Madame ' concaténée avec la chaîne nom puis concaténée avec la chaîne ’ ?’. N’oubliez pas le docstring !!! Correction. 1 def reponse(nom): 2 """ Fonction qui renvoie la chaîne de caractères 'Très bien ! Et vous Madame nom ?' où l'argument nom est une chaîne de caractères""" 3 return 'Très bien ! Et vous Madame '+nom+' ?' b. Les arguments d’une fonction 4 Les fonctions précédentes ne possédaient qu’un seul argument. Mais bien-sûr, une fonction peut en posséder plusieurs. Dans ce cas, ils sont séparés par des virgules lors de la définition ou de l’appel de la fonction. Par exemple, définissons une fonction qui calcule la distance euclidienne entre un point (x, y) de R2 et le point (0, 0) : 1 from numpy import sqrt # On a besoin de la fonction racine carrée ici 2 3 def dist(x,y): 4 """ Calcule la distance euclidienne entre (x,y) et (0,0) où x,y sont des int ou des float """ 5 return sqrt(x**2+y**2) Testons cette fonction pour différents points (1, 1), (1000, 200), (3.5, −7.2) : 1 dist(1,1) 2 dist(1000,200) 3 dist(3.5,-7.2) Exercice 2. Définir une fonction distance qui prend pour arguments euclidienne entre les points (x1 , y1 ) et (x2 , y2 ) de R2 . x1,y1,x2,y2 et qui retourne la distance d...dddocstring !!! Correction. 1 def distance(x1,y1,x2,y2): 2 """ Calcule la distance euclidienne entre (x1,y1) et (x2,y2) où x1,y1,x2,y2 sont des int ou des float """ 3 return sqrt((x1-x2)**2+(y1-y2)**2) On vient de voir comment passer plusieurs arguments à une fonction. Quand on définit une fonction de cette façon, les arguments demandés sont obligatoires : pour appeler la fonction, il faut lui fournir une valeur pour chaque argument de la liste sous peine de recevoir un beau message d’erreur de Python (par exemple, on peut essayer distance(1,1,2) pour voir que Python sais très bien compter !). Dans certains cas, on aimerait avoir des arguments optionnels : c’est-à-dire que si on fournit ces arguments à la fonction, elle en tiendra compte, mais si on ne les fournit pas, alors elle prendra à leur place des valeurs prédéfinies à l’avance que l’on appelle valeurs par défaut. En Python, rien de plus facile, il suffit de préciser la valeur par défaut juste après après un argument que l’on veut rendre optionnel en les séparant par un =. ATTENTION : les arguments optionnels doivent toujours être placés après les arguments obligatoires dans la définition d’une fonction. Exemple, une fonction venucomment qui prend un paramètre obligatoire moment (str) et un paramètre optionnel transport (str) de valeur par défaut 'voiture' et qui renvoie un str ’Ce moment, je suis venu en transport’ : 5 1 def venuquandcomment(moment,transport='voiture'): 2 """ Retourne le str 'Ce moment, je suis venu en transport' où moment et transport sont des str et la valeur par défaut de transport est 'voiture'.""" 3 return 'Ce '+moment+', je suis venu en '+transport Testons : 1 venuquandcomment('matin') 2 venuquandcomment('Jeudi',transport='nageant') Remarquez une chose importante ici : quand je veux fournir une valeur au paramètre optionnel, je DOIS d’abord l’appeler par son nom puis définir sa valeur après un = dans l’appel de la fonction. Ce n’est pas nécessaire ici, mais lorsque la fonction admet plusieurs arguments optionnels, c’est bien-sûr obligatoire (sinon la fonction ne peut pas savoir quel argument optionnel vous avez fourni). Exercice 3. Définir une fonction diagonale — qui prend pour arguments des int ou float l (c’est un ℓ) et L où l’argument L est optionnel de valeur par défaut 10 ; — qui renvoie la mesure d’une diagonale d’un rectangle de largeur l et de longueur L. Correction. 1 from numpy import sqrt # si ce n'est pas déjà fait 2 3 def diagonale(l,L=10): 4 """ Retourne la mesure d'une diagonale d'un rectangle de largeur l et de longueur L où l et L sont des int ou float et L a pour valeur par défaut 10.""" 5 return sqrt(l**2+L**2) c. Portée des variables Comme on l’a vu dans notre toutes première fonction bonjour, on peut définir et utiliser des variables à l’intérieur d’une fonction. Dans bonjour, nous avons utilisé une variable resultat. Essayons d’y accéder en tapant dans le shell : 1 resultat Que nous dit Python ? Et bien que cette variable n’existe pas ! Pourtant nous l’avions bien définie et utilisée dans bonjour. Que s’est-il passé ? En fait, les variables ont une portée : les variables que nous définissons directement dans le shell ou en 6 exécutant une instruction du type L=2 dans l’éditeur ont une portée globale c’est-à-dire que tant que Python est en route, on peut lui demander la valeur de cette variable, il nous la retournera. Par opposition, les variables que nous définissons dans une fonction ont une portée locale : cette variable n’est définie et sa valeur n’est accessible que dans la fonction en question. Pour mieux comprendre le principe, effectuons les tests suivants : 1 2 3 4 5 6 7 8 9 L=2 def f(): x=L return x f() x Que se passe-t-il à l’appel de x ? 1 def f2(): 2 L=5 # définition locale de L 3 return L 4 5 f2() 6 7 L # récuperation de la valeur globale définie dans l'exemple précédent ! On voit bien ici que dans une fonction, même si la variable est définie globalement, la définition locale du même nom n’interfère pas ! On peut tout de même créer des variables définies globalement dans une fonction : on utilise l’instruction global suivi du nom de la variable avant de définir sa valeur : 1 def f3(): 2 global L 3 L=100 4 return L 5 6 f3() 7 8 L 7