Introduction à l'Algorithmie et à Python III

📌 Ecole nationale des chartes, Master TNAH, 2020


Alix Chagué

đŸ“« alix.chague@inria.fr

đŸ’Œ IngĂ©nieure Recherche et DĂ©veloppement @ Inria

inria inria

Crédits

Librement inspiré des supports de cours de Gaël Guibon
Librement inspiré des supports de cours de Julien Pilla

Retrouver l'ensemble du cours sur 👉 github.com/alix-tz/enc-intro-algo👈

Syllabus

Récapitulatif

  • variables (nom, affectation de valeur, type)
  • fonctions built-in et mots rĂ©servĂ©s
  • opĂ©rations arithmĂ©tiques et retypage
  • comparer des valeurs
  • opĂ©rateurs boolĂ©ens
  • conditions (si... alors)
  • rĂ©pĂ©tition (tant que / rĂ©pĂ©ter x fois)

Plan du cours

  • Syllabus
  • Fonctions
  • Import et modules
  • Nouveau type : listes
  • Nouveau type : dictionnaires (et tuples)
  • Aller plus loin

Liens utiles

👉 Simulateur d'environnement Python en mode pseudo-IDE : https://repl.it/languages/python3

👉 Simulateur d'environnement Python en mode console : https://www.python.org/shell/

👉 Documentation officielle de Python : https://docs.python.org/3/

👉 Visualisateur d'exĂ©cution de code Python : http://pythontutor.com/

Quelques ressources pour continuer à se former

👉 "Automate the Boring Stuff with Python" (en) : https://automatetheboringstuff.com/

👉 Leçons dĂ©diĂ©es Ă  Python sur Programming Historian (en, fr ou es) : https://programminghistorian.org/en/lessons/introduction-and-installation

👉 "Apprendre Ă  coder avec Python", MOOC de l'UniversitĂ© Libre de Bruxelles (fr) : https://www.fun-mooc.fr/courses/course-v1:ulb+44013+session04/about

👉 "Apprenez à programmer en Python", cours en ligne sur OpenClassroom (fr) : https://openclassrooms.com/fr/courses/235344-apprenez-a-programmer-en-python

👉 "Introduction Ă  Python" pour le Master IngĂ©nierie Multilingue de l'Inalco, LoĂŻc Grobol et Yoann Dupont (fr) : https://loicgrobol.github.io/python-im/m2-2018/

Fonctions

Une fonction est une suite d'instructions rassemblĂ©es sous un nom et que l'on peut appeler dans un programme. On dit qu'une fonction renvoie ou retourne une valeur une fois que l'ensemble des instructions qu'elle contient ont Ă©tĂ© exĂ©cutĂ©es. Cette valeur peut ĂȘtre nulle (None) ou essentielle Ă  l'exĂ©cution du reste du programme.

On a vu qu'il existe des fonctions built-in (ex : print()), mais l'utilisateur-rice peut aussi créer ses propres fonctions, souvent pour simplifier le code en créant des unités logiques.

Pour crĂ©er une fonction, on utilise le mot-clef def suivi du nom que l'on souhaite donner Ă  la fonction, suivi de parenthĂšses puis de deux points (():). Pour mettre fin Ă  la dĂ©claration de la fonction, on utilise le mot-clef return. Il peut ĂȘtre suivi d'une valeur ou ĂȘtre utilisĂ© seul

Les instructions décrites à l'intérieur d'une fonction ne sont pas exécutées tant que la fonction n'est pas appelée. Pour appeler une fonction on utilise son nom, suivi de parenthÚses. Une fonction peut appeler une autre fonction.

Exemple 1

Je crée une fonction nommée dit_coucou dont le seul but est d'afficher "Coucou !".

In [6]:
# je crée une fonction
def dit_coucou():
    print("Coucou !")
    return
    
# j'appelle la fonction
dit_coucou()
Coucou !

Précision sur les renvois

En Python, les trois dĂ©clarations suivantes mĂšnent au mĂȘme rĂ©sultat :

In [7]:
def dit_coucou():
    print("Coucou !")
    return None

def dit_coucou():
    print("Coucou !")
    return

def dit_coucou():
    print("Coucou !")

Cela signifie qu'en Python, le mot-clef return n'est pas obligatoire si l'on ne renvoie pas de valeur à la fin de la fonction. En fait, la fin de l'indentation suffit à signaler la fin de la déclaration de la fonction.

Quand une fonction renvoie une valeur, on peut la stocker dans une variable pour l'utiliser ensuite.

In [8]:
def combien_font_trois_plus_trois():
    return 3 + 3

resultat = combien_font_trois_plus_trois()  # on peut stocker le résultat
print(combien_font_trois_plus_trois())  # ou interagir avec directement
6

Arguments

Les parenthÚses ne sont pas ici pour faire joli. Comme avec les fonctions en mathématiques, elles servent à faire passer une ou plusieurs valeurs (arguments ou paramÚtres) qui seront utilisées pour exécuter les instructions définies dans la fonction.

Les arguments sont en quelque sorte des variables qui n'existent que durant le temps d'exécution de la fonction. Pour désigner ce phénomÚne, on parle de la portée (scope) d'une variable.

In [9]:
def dit_moi_coucou(nom):
    print("Coucou", nom, "!")
    
mon_prenom = "Alix"
dit_moi_coucou(mon_prenom)
Coucou Alix !

Si j'essaie de faire appel à la variable nom en dehors du bloc de définition de la fonction "dit_moi_coucou", ça ne fonctionne pas

In [10]:
print(nom)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-10-c427005c1d14> in <module>
----> 1 print(nom)

NameError: name 'nom' is not defined

Récapitulons les concepts

On a parlé de définition de fonction, d'appel de fonction, d'arguments, de renvois et de scope.

illustration de la définition d'une fonction

Exemple 2

In [11]:
def afficher_lavariable_son_type_et_sa_valeur(lavariable):
    print("la variable", type(lavariable), lavariable, sep=" | ")
    return "C'est fait!"

le_nom_de_mon_chat = "Query"
print(afficher_lavariable_son_type_et_sa_valeur(le_nom_de_mon_chat))
la variable | <class 'str'> | Query
C'est fait!
  1. Je crée une fonction, dont le nom est trÚs (trop) explicite, intitulée afficher_lavariable_son_type_et_sa_valeur()
    • Cette fonction reçoit une valeur dans une variable nommĂ©e lavariable
    • La fonction prĂ©voit l'affichage de la chaĂźne de caractĂšres "la variable", du type de la valeur contenue dans la variable lavariable, puis de cette valeur, le tout sĂ©parĂ© par "|'
    • ArrivĂ©e Ă  la fin des instructions prĂ©vues dans cette fonction, la fonction retournera une chaĂźne de caractĂšres contenant "C'est fait!"
  2. Je crée une variable le_nom_de_mon_chat qui contient la chaßne de caractÚres "Query"
  3. Je passe la valeur contenue dans la le_nom_de_mon_chat à la fonction afficher_lavariable_son_type_et_sa_valeur() et j'affiche la valeur retournée

À quel moment choisit-on de définir une fonction ?

Il n'y a pas de rÚgle qui définisse qu'à tel ou tel moment il faut créer une fonction. C'est une affaire de pratique, de choix dans l'organisation du code et de lisibilité de celui-ci.

Souvent, on fait une fonction pour un ensemble logique d'actions.

Par exemple dans un programme qui génÚre des tweets illustrés, une fonction crée un texte et une image, une fonction enregistre l'image localement, une fonction envoie le texte et l'image sur Twitter. Décomposer ainsi le code permet de faire ressortir les grandes étapes de traitement.

Souvent, aussi, on crée une fonction que l'on réutilisera par la suite dans d'autres projets, on évite ainsi de recréer un élément du code qu'on a déjà rédigé.

Par exemple, une fonction pour lister l'ensemble des fichiers contenus dans un dossier.

Organisation du code

Pour faciliter la lecture d'un script, on rassemble l'ensemble des définitions de fonction avant de passer au groupe d'instruction principal, qui contiendra les appels de fonctions.

# définition de la fonction 1
# définition de la fonction 2
# définition de la fonction 3
# --------
# instructions
# appel de la fonction 1
# instructions
# appel de la fonction 1
# appel de la fonction 3
# instructions
# appel de la fonction 2

Exercices pratiques

Faire les 5 exercices du fichier fonctions.py

👉 https://repl.it/@AlixChagu/ENCintroalgo#basics/fonctions.py

Libraries, imports et modules

Importer des fonctions externes

À part les fonctions built-in et les fonctions crĂ©Ă©es de toutes piĂšces, il est possible d'utiliser des fonctions dĂ©jĂ  dĂ©finies par d'autres dĂ©veloppeur·ses.

Pour faire simple, ces fonctions sont enregistrées dans des libraries (ou package) que l'on importe dans un programme pour pouvoir s'en servir. On parle aussi de dépendances.

Certaines libraries sont built-ins : elles sont toujours disponibles, il suffit de les activer. D'autres doivent ĂȘtre installĂ©es avant de pouvoir ĂȘtre activĂ©es. On utilise pour cela un gestionnaire de paquets (comme pip).

Quelques exemples de libraries built-in que vous rencontrerez rapidement : os, csv, random.

Pour activer une library, il suffit de l'importer au tout début du script avec le mot-clef import, suivi du nom de la library.

In [12]:
import os  # on peut désormais utiliser les fonctions de la library os.
import random  # on peut désormais utiliser les fonctions de la library random.

Pour utiliser une fonction issue d'une library, il faut rappeler son nom, puis appeler le nom de la fonction comme on le ferait avec une fonction définie localement.

Cela se fait selon le modĂšle suivant : nom_du_paquet.nom_de_la_fonction()

In [13]:
# random possÚde une fonction appelée randint() qui permet de générer un nombre entier au hasard 
# compris entre a et b.
print(random.randint(0, 100))
82

Organisation du code

Pour faciliter la lecture d'un script, les imports se font au tout début du script.

# imports
# --------
# définition de la fonction 1
# définition de la fonction 2
# définition de la fonction 3
# --------
# instructions
# appel de la fonction 1
# instructions
# appel de la fonction 1
# appel de la fonction 3
# instructions
# appel de la fonction 2

Nouveau type : Listes

📜 Les listes sont un type de variable pouvant contenir une ou plusieurs valeurs à la suite.

📜🐍 En Python, une liste peut contenir plusieurs types de variables en mĂȘme temps.

đŸ“œđŸ€š En fonction des langages de programmation, on les appelle aussi array ou vecteur.

📜 Une liste est un objet appartenant Ă  la catĂ©gorie des iterables (comme les chaines de caractĂšres)

📜 Les valeurs contenues dans une liste sont indexĂ©es. On peut donc cibler prĂ©cisĂ©ment telle ou telle valeur contenue dans la liste.

đŸ“œđŸ€Ż L'indexation dans une liste commence Ă  0

Syntaxe

In [14]:
# créer une liste
ma_liste_vide = []
mon_autre_liste_vide = list()
ma_liste = ['A','B','C','D']

# Accéder au contenu d'une liste
print('ma_liste[2]  :', ma_liste[2])
une_variable = ma_liste[1]
print('une_variable :', une_variable)


# Une liste peut contenir plusieurs types... y compris des listes
super_liste = ["ceci n'est pas un chiffre", 3.14, True, type('hello'), 2048, ma_liste]
print('super_liste  :', super_liste)
ma_liste[2]  : C
une_variable : B
super_liste  : ["ceci n'est pas un chiffre", 3.14, True, <class 'str'>, 2048, ['A', 'B', 'C', 'D']]

Indexation

Moyen mnémotechnique : l'indexation des listes fonctionne comme les étages en France.

index 0 1 2 3
valeur A B C D
palier RDC 1E 2E 3E

Si vous demandez un index qui n'est pas associé à une valeur (parce que la liste est trop courte), vous obtenez une erreur (IndexError).

In [15]:
print(ma_liste[4])
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-15-b214c2428d1f> in <module>
----> 1 print(ma_liste[4])

IndexError: list index out of range

Indexation par la fin

On peut viser un emplacement dans la liste en partant du début ou de la fin.

In [16]:
liste_exemple = ["RDC", "1er", "2e", "3e", "4e"]
print(liste_exemple[-1])
print(liste_exemple[-3])
4e
2e
In [17]:
print(liste_exemple[-10])
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-17-c4b99e6a1b85> in <module>
----> 1 print(liste_exemple[-10])

IndexError: list index out of range

Bonnes pratiques

Pour éviter les déconvenues, pensez à utiliser len() sur une liste avant de cibler les valeurs indexées.

In [18]:
print(len(liste_exemple))
5
In [19]:
print(liste_exemple[len(liste_exemple) - 1])
4e
In [20]:
index = 6
if index < len(liste_exemple):
    print(liste_exemple[index])
else:
    print("No can't do!")
No can't do!

Sections, sublists ou encore slices

Si on peut cibler une seule valeur à la fois, on peut aussi cibler une section dans une liste : liste[début:fin:pas]

In [2]:
exemple = ['p','y','t','h','o','n', ' ', '!']
print(exemple[2:6])
['t', 'h', 'o', 'n']
0 1 2 3 4 5 6 7
"P" "Y" "T" "H" "O" "N" " " "!"
- - start - - - stop -
In [3]:
# on peut utiliser des index négatifs
print('1 :', exemple[-6:-2])    
1 : ['t', 'h', 'o', 'n']
In [4]:
# en parcourant la liste de gauche Ă  droite
print('2 :', exemple[-2:-6])  
2 : []
In [5]:
# le pas de 1 est implicite, on peut le modifier
print('3 :', exemple[2:6:2])  
3 : ['t', 'o']
In [6]:
# sans index de fin, on continue jusqu'Ă  la fin de la liste 
print('4 :', exemple[2:])     
4 : ['t', 'h', 'o', 'n', ' ', '!']
In [7]:
# sans index de début, on part du début de la liste
print('5 :', exemple[:5])     
5 : ['p', 'y', 't', 'h', 'o']
In [8]:
# on peut faire une section allant du début à la fin (copie)
print('6 :', exemple[:])      
6 : ['p', 'y', 't', 'h', 'o', 'n', ' ', '!']
In [9]:
# on peut ne préciser que le pas
print('7 :', exemple[::2])    
7 : ['p', 't', 'o', ' ']
In [10]:
# n'importe lequel des Ă©lĂ©ments peut ĂȘtre implicite
print('8 :', exemple[:5:2]) 
8 : ['p', 't', 'o']

Itérables

Une chaßne de caractÚres fait aussi partie de la catégorie des itérables, on peut donc se servir des slices et des index sur ce type de valeur.

In [23]:
chaine = 'python !'
print(chaine[len(chaine) - (len(chaine)*2)])
print(chaine[2:6])
p
thon

En revanche, dans une chaßne de caractÚres, on ne peut pas réassigner une valeur à un index. On dit qu'une chaßne de caractÚres est immutable.

In [24]:
chaine[4] = '*'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-24-b6a7f31ceb5f> in <module>
----> 1 chaine[4] = '*'

TypeError: 'str' object does not support item assignment
In [25]:
# mais on peut toujours contourner ce problĂšme...
modif = chaine[:3] + '*' + chaine[4:]
print(modif)
pyt*on !

Méthodes des listes

Les listes ont des fonctions et méthodes qui leur sont associées.

  • liste.append(x) : ajouter un Ă©lĂ©ment Ă  la fin de la liste
  • liste.pop({index}) : supprimer un Ă©lĂ©ment de la liste Ă  partir de son index (le rĂ©cupĂ©rer en mĂ©moire)
  • liste.remove(x) : supprimer de la liste la premiĂšre occurrence de l'Ă©lĂ©ment recherchĂ©
  • liste.index(x) : renvoyer l'index de la premiĂšre occurrence de l'Ă©lĂ©ment recherchĂ©
  • liste.count(x) : compter le nombre d'occurrence de l'Ă©lĂ©ment recherchĂ© dans la liste
  • liste.sort() : trier la liste selon un ensemble de rĂšgles
In [26]:
liste_1a4 = [1, 2, 3, 4]
liste_5a8 = [5, 6, 7, 8]
liste_lettres = ['Q', 'Z', 'S', 'D']

# On peut concaténer 2 listes
liste_1a8 = liste_1a4 + liste_5a8
print(liste_1a8)

# Attention .append() n'a pas le mĂȘme effet
liste_1a8.append(liste_lettres)
print(liste_1a8)
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8, ['Q', 'Z', 'S', 'D']]

Nouveau type : Dictionnaires

🔑 Les dictionnaires sont un type de variable contenant une sĂ©rie de valeurs associĂ©es Ă  des clefs d'accĂšs.

🔑 Contrairement aux listes, les dictionnaires n'ont pas d'index (ce ne sont pas des itĂ©rables).

🔑 Comme les listes, les dictionnaires peuvent contenir plusieurs types de donnĂ©es en mĂȘme temps, y compris d'autres dictionnaires.

🔑 Un dictionnaire peut contenir plusieurs fois la mĂȘme valeur mais chaque clef doit ĂȘtre unique.

Syntaxe

In [27]:
# créer un dictionnaire
mon_dico_vide = {}
mon_autre_dico_vide = dict()
mon_dico = {"clef" : "valeur"}

print("mon_dico =", mon_dico)

# Ajouter ou modifier des valeurs dans un dictionnaire
print("mon_dico_vide =", mon_dico_vide)
mon_dico_vide["hello"] = "world"
print("mon_dico_vide =", mon_dico_vide)
mon_dico_vide["hello"] = "world!"
print("mon_dico_vide =", mon_dico_vide)

# Supprimer une valeur dans un dictionnaire
del mon_dico_vide["hello"]
print("mon_dico_vide =", mon_dico_vide)
mon_dico = {'clef': 'valeur'}
mon_dico_vide = {}
mon_dico_vide = {'hello': 'world'}
mon_dico_vide = {'hello': 'world!'}
mon_dico_vide = {}
In [28]:
# Accéder au contenu d'un dictionnaire
print('mon_dico["clef"] =', mon_dico["clef"])

# Un dictionnaire peut contenir plusieurs types... y compris des dictionnaires
super_dico = {"chiffre": 42, 113: "entier", "clef3" : [1,2,3]}
print('super_dico  :', super_dico)
mon_dico["clef"] = valeur
super_dico  : {'chiffre': 42, 113: 'entier', 'clef3': [1, 2, 3]}

Dans certains cas, utiliser un dictionnaire plutÎt qu'une liste permet de naviguer plus facilement entre les données qu'il contient.

identité = ["Berthe", "Morisot", 1865, 1841, 1895]
identité = {"prénom": "Berthe", "nom": "Morisot", "debut": 1865, "naissance": 1841, "mort": 1895}

Méthodes des dictionnaires

  • dico.keys() : crĂ©er un objet itĂ©rable contenant la liste des clefs utilisĂ©es dans le dictionnaire
  • dico.values() : crĂ©er un objet itĂ©rable contenant la liste des valeurs contenues dans le dictionnaire
  • dico.get() : envoie la valeur associĂ©e Ă  la clef recherchĂ©e ou une valeur par dĂ©faut si la clef n'existe pas
  • dico.items() : renvoie le contenu du dictionnaire sous la forme d'une liste de tuples.
In [29]:
dico_demo = {"prénom": "Berthe", "nom": "Morisot", "debut": 1865, "naissance": 1841, "mort": 1895}
In [30]:
# .keys()
print(dico_demo.keys())
print(type(dico_demo.keys()))
for key in dico_demo.keys():
    print(key)
dict_keys(['prénom', 'nom', 'debut', 'naissance', 'mort'])
<class 'dict_keys'>
prénom
nom
debut
naissance
mort
In [31]:
# .values()
print(dico_demo.values())
print(type(dico_demo.values()))
for value in dico_demo.values():
    print(value)
dict_values(['Berthe', 'Morisot', 1865, 1841, 1895])
<class 'dict_values'>
Berthe
Morisot
1865
1841
1895
In [32]:
# .get(key, default)
print(dico_demo.get('prénom'))
print(dico_demo.get('métier'))
print(dico_demo.get('métier', 'métier inconnu'))
Berthe
None
métier inconnu
In [33]:
# .items()
print(dico_demo.items())
print(type(dico_demo.items()))
for duo in dico_demo.items():
    print(type(duo), duo, sep=" ; ")
dict_items([('prénom', 'Berthe'), ('nom', 'Morisot'), ('debut', 1865), ('naissance', 1841), ('mort', 1895)])
<class 'dict_items'>
<class 'tuple'> ; ('prénom', 'Berthe')
<class 'tuple'> ; ('nom', 'Morisot')
<class 'tuple'> ; ('debut', 1865)
<class 'tuple'> ; ('naissance', 1841)
<class 'tuple'> ; ('mort', 1895)

Exercices pratiques

RĂ©aliser les 5 exercices du fichier listes_et_dico.py

👉 https://repl.it/@AlixChagu/ENCintroalgo#basics/listes_et_dico.py

Aller plus loin

  • Listes en comprĂ©hension
  • Programmation modulaire
  • JSON et CSV
  • Manipulation de fichiers
  • Documenter son code
  • Tests et exceptions
  • Classes et programmation orientĂ©e objets

FIN

Prof Chen: "Un tout nouveau monde de rĂȘves, d'aventures et de Python t'attend! Dingue!"