Apprendre Python : Algorithmie
Variables, tableaux, conditions, boucles, fonctions... Découvrons la syntaxe de base de Python pour écrire des algorithmes.
Par définition, un algorithme est caractérisé par un ensemble d’opérations ordonnées et finies devant être suivies dans l’ordre pour résoudre un problème. On assemble plusieurs algorithmes entre eux pour créer un programme informatique.
Un algorithme est une reproduction automatisée d’un raisonnement de l’homme.
Pour retranscrire nos raisonnements, on fait appel à de nombreux composants algorithmiques qui constituent la syntaxe de nos algorithmes. Étudions ensemble les concepts élémentaires et leur syntaxe en Python.
Commentaires
Dans un langage de programmation, un commentaire sert à ajouter des notes ou explications pour les développeurs, sans affecter le code exécuté.
En Python, il est possible d’écrire des commentaires dans son code source avec le caractère #
.
# Je suis un commentaire
# Je suis un commentaire que l'on peut écrire
# sur plusieurs lignes
Données
Il serait difficile de réaliser un algorithme sans pouvoir stocker des données. Découvrons comment déclarer des variables, constantes, listes et dictionnaires en Python.
Variables
Une variable est une case mémoire dans laquelle il est possible de stocker une information, une donnée. Cette case mémoire sera identifiée par un nom.
La valeur stockée peut être de nombreux types, dont les 3 principaux sont :
- Nombre : entier, décimal…
- Chaîne de caractères : caractère unique, chaîne courte, chaîne longue… - s’écrit entre guillemets simples
' '
ou doubles" "
. - Booléen : vrai (
True
) ou faux (False
) - …
firstname = "toto"
weight = 58.5
hungry = True
Quand on affecte une valeur à une variable on dit qu’on l’initialise.
my_variable # Erreur : name 'my_variable' is not defined
Constantes
Une constante est similaire à une variable, à la seule différence que sa valeur ne pourra pas changer. Il s’agit d’une donnée en lecture seule.
Python n’implémente pas directement la gestion des constantes, le styleguide PEP8 recommande donc de les déclarer comme des variables classiques, à la seule différence de faire usage de la UPPER_CASE
.
MAX_SPEED = 90
Listes
Les listes sont en quelque sorte des super variables pour stocker plusieurs informations, de manière structurée.
Déclaration
On les déclare de la même manière que des variables classiques.
Concernant leurs valeurs, on les écrit entre crochets []
. On sépare les valeurs avec des virgules.
fruits = ["Pomme", "Poire", "Banane"]
Il est également possible de stocker une liste dans une liste ! À la différence des listes unidimensionnelles précédentes, on appellera une liste de ce type : liste multidimensionnelle ou liste imbriquée.
Pour une meilleure lisibilité, on indentera généralement les sous-listes :
users = [
["Pierre", "Moulin", 34],
["Paul", "Dupont", 27],
["Jacques", "Durand", 31]
]
Accès aux éléments
Pour accéder aux données stockées dans une liste, on les extrait par leur indice.
Chaque valeur stockée dans une liste est associée à un indice, commençant à 0
. Pour récupérer une valeur, on fait : nom_liste[indice_valeur]
:
fruits = ["Pomme", "Poire", "Banane"]
print(fruits[0]) # Affiche "Pomme"
print(fruits[1]) # Affiche "Poire"
print(fruits[2]) # Affiche "Banane"
print(fruits[3]) # Erreur ! Affiche "IndexError: list index out of range", car on sort du tableau
Les indices négatifs permettent d’accéder aux éléments en partant de la fin de la liste.
fruits = ["Pomme", "Poire", "Banane"]
print(fruits[-1]) # Affiche "Banane"
print(fruits[-2]) # Affiche "Poire"
print(fruits[-3]) # Affiche "Pomme"
Considérez la liste suivante :
word = ["l", "a", "C", "o", "n", "s", "o", "l", "e"]
Voici un tableau récapitulant le fonctionnement des indices pour accéder aux éléments de la liste.
Valeur | Indice Positif | Indice Négatif |
---|---|---|
l | 0 | -9 |
a | 1 | -8 |
C | 2 | -7 |
o | 3 | -6 |
n | 4 | -5 |
s | 5 | -4 |
o | 6 | -3 |
l | 7 | -2 |
e | 8 | -1 |
Le caractère :
permet par ailleurs de spécifier des tranches (slices) à extraire d’une séquence comme une liste.
fruits = ["Pomme", "Poire", "Banane", "Fraise", "Pêche"]
# De l'indice 2 à 4 (exclu)
print(fruits[2:4]) # Affiche ["Banane", "Fraise"]
# Du début à l'indice 4 (exclu)
print(fruits[:4]) # Affiche ["Pomme", "Poire", "Banane", "Fraise"]
# De l'indice 4 à la fin
print(fruits[4:]) # Affiche ["Pêche"]
# Tous les éléments de la liste en prenant un pas de 2
print(fruits[::2]) # Affiche ["Pomme", "Banane", "Pêche"]
Extraction d'une chaîne de caractères
Le caractère :
s’avère également utile pour trancher des chaînes de caractères :
message = "Hello from laConsole"
print(message[11:]) # Affiche 'laConsole'
message[11:]
retourne la sous-chaîne à partir du caractère à l’indice 11
jusqu’à la fin.
Pour accéder aux éléments d’une liste imbriquée (multidimensionnelle), on spécifiera un indice pour chaque dimension :
users = [
["Pierre", "Moulin", 34],
["Paul", "Dupont", 27],
["Jacques", "Durand", 31]
]
print(users[1]) # Affiche ["Paul", "Dupont", 27]
print(users[1][2]) # Affiche 27
Modification
Pour modifier des éléments dans une liste, vous pouvez accéder directement aux éléments par leur indice et les modifier.
fruits = ["Pomme", "Poire", "Banane"]
fruits[1] = "Fraise" # Remplace "Poire" par "Fraise"
Suppression
Pour supprimer des éléments d’une liste, vous pouvez utiliser le mot-clé del
.
fruits = ["Pomme", "Poire", "Banane"]
del fruits[1] # fruits = ["Pomme", "Banane"]
Dictionnaires
Les dictionnaires sont des structures de données complexes et flexibles permettant d’organiser et manipuler les données de votre programme.
En Python, un dictionnaire consiste à stocker des paires d’informations identifiées par des clés et définies par leurs valeurs.
- Clé : Décrit quel genre de données est attendu.
- Valeur : Pouvant être de n’importe quel type de données (texte, nombre, booléen… y compris des listes ou d’autres dictionnaires).
Déclaration
On déclare un dictionnaire en utilisant des accolades {}
avec :
- Les paires clé-valeur séparées par des deux-points
:
- Chaque paire séparée par une virgule
,
user = {
"firstname": "Camille",
"age": 30,
"city": "Bordeaux"
}
La clé doit être écrite entre guillemets simples (''
) ou doubles (""
), à la manière du format JSON.
Décomposer : déclarer puis initialiser
Il est tout à fait possible de décomposer en 2 temps :
- La déclaration du dictionnaire
- L’initialisation de paires
user = {}
user["firstname"] = "Camille"
Il est possible d’avoir des dictionnaires à l’intérieur d’autres dictionnaires, créant ainsi des structures de données plus complexes.
user = {
"identity": {
"firstname": "Camille",
"age": 30
},
"address": {
"street": "123 Rue de la République",
"city": "Bordeaux",
"postal_code": "33000",
"country": "France"
}
}
Pour encore plus de potentiel, on peut également mettre ces dictionnaires au sein de listes :
users = [
{
"identity": {
"firstname": "Camille",
"age": 30
},
"address": {
"street": "123 Rue de la République",
"city": "Bordeaux",
"postal_code": "33000",
"country": "France"
}
},
{
"identity": {
"firstname": "Arthur",
"age": 25
},
"address": {
"street": "45 Avenue des Champs-Élysées",
"city": "Paris",
"postal_code": "75008",
"country": "France"
}
}
]
Accès aux éléments
Contrairement aux listes, où on accède aux éléments par leur indice, on accède aux éléments d’un dictionnaire par des clés uniques, toujours spécifiées entre crochets []
.
user = {
"name": "Camille",
"age": 30,
"city": "Bordeaux"
}
print(user["name"]) # Affiche "Camille"
print(user["age"]) # Affiche 30
Pour accéder aux éléments d’un dictionnaire imbriqué, on spécifiera la clé relative aux niveaux d’imbrication souhaités :
user = {
"identity": {
"firstname": "Camille",
"age": 30
},
"address": {
"street": "123 Rue de la République",
"city": "Bordeaux",
"postal_code": "33000",
"country": "France"
}
}
print(user["identity"]) # Affiche {'firstname': 'Camille', 'age': 30}
print(user["address"]["city"]) # Affiche "Bordeaux"
Pour accéder à un élément au sein d’une liste de dictionnaires, on procède en combinant indice et clé.
users = [
{
"identity": {
"firstname": "Camille",
"age": 30
},
"address": {
"street": "123 Rue de la République",
"city": "Bordeaux",
"postal_code": "33000",
"country": "France"
}
},
{
"identity": {
"firstname": "Arthur",
"age": 25
},
"address": {
"street": "45 Avenue des Champs-Élysées",
"city": "Paris",
"postal_code": "75008",
"country": "France"
}
}
]
print(users[0]["identity"]) # Affiche {'firstname': 'Camille', 'age': 30}
print(users[1]["address"]["city"]) # Affiche "Paris"
Modification
On peut modifier la valeur associée à une clé existante en y accédant par son indice et en lui affectant une nouvelle valeur.
user["age"] = 31
Suppression
Tout comme pour les listes, pour supprimer une paire clé-valeur, on utilise le mot-clé del
en spécifiant la clé de la paire à supprimer.
del user["city"]
Traitement
Stocker des données, c’est bien… les manipuler, c’est mieux. Pour cela, place aux opérations, conditions, boucles et fonctions !
Opérations élémentaires
Opérations arithmétiques
En Python, il est possible d’additionner, soustraire, multiplier, diviser des variables entre elles en utilisant les opérateurs arithmétiques élémentaires +
, -
, *
et /
. Il est même possible de calculer le modulo (reste de la division) de deux nombres avec l’opérateur %
.
a = 4
b = 7
# Somme de 2 variables
addition = a + b
# Soustraction de 2 variables
soustraction = b - a
# Multiplication de 2 variables
multiplication = a * b
# Division de 2 variables
division = b / a
# Modulo de 2 variables
modulo = b % a
# Note : pour les opérations plus complexes (racine carrée, exponentielle, factorielle...), on fera appel à des fonctions
Concaténation
Si vous souhaitez afficher des variables à côté de chaînes de caractères ou à côté d’autres variables (concaténation), on utilise l’opérateur +
.
firstname = "James"
lastname = "Bond"
sentence = lastname + ", " + firstname + " " + lastname
print(sentence) # Affiche "Bond, James Bond"
Découvrir les f-strings
Si vous souhaitez concaténer des résultats lors de leur affichage avec la fonction print()
, il est également possible d’utiliser les f-strings en précédant le texte par le caractère f
et en délimitant la/les variable(s) par des accolades {variable}
.
firstname = "James"
lastname = "Bond"
print(f"{lastname}, {firstname} {lastname}") # Affiche "Bond, James Bond"
Cette syntaxe s’avère plus concise lors de concaténations multiples, en évitant de fermer-ouvrir-fermer-ouvrir… la chaîne de caractères.
Conditions
Les conditions sont des structures algorithmiques extrêmement fréquentes et utiles qui se traduisent par « fais ceci, si cela ». Notre cerveau analyse constamment des situations conduisant à la prise de décision.
if
, elif
, else
On déclare une condition avec le mot-clé if
(littéralement « si »).
Une condition s’écrit de la forme if <condition>: traitement
- Si la condition est vraie : renvoie
True
. - Si la condition est fausse : renvoie
False
.
Mais alors comment écrire ces conditions ? Avec des opérateurs de comparaison.
Opérateurs de comparaison
Il existe 6 grands opérateurs de comparaison.
Opérateur | Usage | Description |
---|---|---|
== | val1 == val2 | Teste une égalité stricte (valeur + type) |
!= | val1 != val2 | Teste une différence stricte (valeur + type) |
< | val1 < val2 | Teste si une valeur est strictement inférieure à une autre |
> | val1 > val2 | Teste si une valeur est strictement supérieure à une autre |
<= | val1 <= val2 | Teste si une valeur est inférieure ou égale à une autre |
>= | val1 >= val2 | Teste si une valeur est supérieure ou égale à une autre |
Opérateurs logiques
Au nombre de 3, les opérateurs logiques permettent de tester la véracité d’un ensemble de conditions (and
ou or
) mais aussi d’en inverser la logique (not
).
Opérateur | Usage | Description |
---|---|---|
and | expr1 and expr2 | Renvoie True si toutes les comparaisons sont vraies ou False sinon |
or | expr1 or expr2 | Renvoie True si au moins l’une des comparaisons est vraie ou False sinon |
not | not expr | Renvoie False si une comparaison est vraie ou renvoie True dans le cas contraire |
dice = 1
if dice == 1: # Ici, la condition renvoie "true"
print("Il vaut mieux relancer le dé...")
Il est également possible de combiner if
et else
dans une seule instruction pour ajouter des conditions intermédiaires. Cela se fait au travers d’une instruction nommée elif
(pour « else if »).
dice = 5
if dice == 1:
print("Il vaut mieux relancer le dé...")
elif dice > 1 and dice <= 3:
print("C'est mieux...")
elif dice > 3 and dice <= 5:
print("Pas mal !")
Enfin, si aucune condition précédente n’est vérifiée, le mot-clé else
seul permet de déclencher un scénario alternatif.
dice = 5
if dice == 1:
print("l vaut mieux relancer le dé...")
elif dice > 1 and dice <= 3:
print("C'est mieux...")
elif dice > 3 and dice <= 5:
print("Pas mal !")
else:
print("Super !")
Conditions imbriquées
Il est bien évidemment possible d’imbriquer des conditions les unes dans les autres !
note = 13
if 0 <= note <= 20:
if note >= 0 and note < 8:
print("Refusé")
elif note >= 8 and note < 10:
print("Rattrapage !")
elif note >= 10 and note < 12:
print("Admis")
elif note >= 12 and note < 14:
print("Admis avec mention AB")
elif note >= 14 and note < 16:
print("Admis avec mention B")
else:
print("Admis avec mention TB")
else:
print("Note non-valide")
match
Dans l’écriture de raisonnements logiques similaires, le match
propose une syntaxe alternative plus concise et plus lisible pour vérifier des égalités.
fruit = "Banane"
match fruit:
case "Banane":
print(f"{fruit} (1.93 € / kg)")
case "Pomme":
print(f"{fruit} (2.62 € / kg)")
case "Mangue" | "Papaye":
print(f"{fruit} (6.17 € / kg)")
case _:
print(f"Désolé, nous ne vendons pas de {fruit}")
match <valeur>
: valeur à comparer dans les clausescase
.case <expression>
: expression à comparer avec la valeur de base.- Si correspondance, exécution d’une instruction
- Si non-correspondance, passage au
case
suivant
case _
clause exécutée par défaut si aucune correspondance n’est trouvée avec les clausescase
précédentes.
Le symbole |
permet de tester plusieurs valeurs dans un même cas (équivalent à case 'Mangue':
et case 'Papaye':
).
Boucles
Le principe des boucles est de répéter des instructions plusieurs fois.
for
La boucle for
(« pour ») est une boucle à nombre d’itérations fini. Pour cela, elle exploite la fonction range()
, permettant de spécifier 3 paramètres :
- Le point de départ
- Le point d’arrivée
- Le pas (« on va de x en x »)
# Affiche 0, 1, 2, 3... 9
for i in range(10):
print(i)
# Affiche 3, 4, 5... 9
for i in range(3, 10):
print(i)
# Affiche 3, 5, 7, 9
for i in range(3, 10, 2):
print(i)
Si cette fonction possède :
- 1 argument : il s’agit de la valeur d’arrivée (
-1
) - 2 arguments : il s’agit de la valeur de départ et de la valeur d’arrivée (
-1
) - 3 arguments : il s’agit de la valeur de départ, de la valeur d’arrivée (
-1
) et du pas
Il est bien évidemment possible d’imbriquer des boucles les unes dans les autres !
La boucle for
est également très utilisée pour itérer sur des séquences comme des :
- Chaînes de caractères
- Listes
- Dictionnaires
- Etc.
languages = ["HTML", "CSS", "JavaScript", "PHP"]
for language in languages:
print(language) # Affiche "HTML", puis "CSS", etc.
Ici, language
prend successivement les valeurs du tableau languages
.
while
La boucle while
(« tant que ») est une boucle à nombre d’itérations non-défini.
La boucle while
est une sorte de mélange entre structure conditionnelle et structure itérative, dans la mesure où on continue d’itérer tant qu’une condition est vérifiée.
i = 0
while i < 5:
print(i) # Affiche 0, 1, 2, 3, 4
i = i + 1
Fonctions
Les fonctions permettent de regrouper un ensemble d’instructions visant à résoudre une problématique au sein d’un même module. Il est possible de faire appel à un bloc de code de ce type afin qu’il effectue quelque chose et/ou nous retourne un résultat.
Fonctions natives
Comme tout langage de programmation, Python ne déroge pas à la règle et vient avec son lot de fonctions natives. Il suffira alors de les appeler par leur nom.
print("Hello from laConsole")
Il en existe de nombreuses autres comme len()
, type()
, range()
, sum()
…
Fonctions custom
En Python, il est possible de créer ses propres fonctions ; nous parlerons de fonctions « custom ».
Déclaration de fonction
Pour déclarer une fonction custom nous définissons :
- Son nom (comme pour les variables, la PEP 8 recommande de privilégier la
🐍 snake_case
) - Des instructions
- (optionnels) Ses paramètres
- (optionnelle) Une valeur de retour (information retournée par la fonction)
Fonction avec nom
+ instructions
def ma_fonction():
# Instructions...
- On déclare systématiquement une fonction avec le mot-clé
def
- Le nom de la fonction est suivi de parenthèses
()
- Après
:
, on écrit les instructions à exécuter par la fonction, en veillant bien à les indenter
Fonction avec nom
+ instructions
+ paramètres
+ valeur de retour
def ma_fonction(param1, param2):
# Instructions...
return ...
- Dans les parenthèses de la fonction
()
, on peut spécifier des paramètres (= informations transmises à la fonction) - Après le mot-clé
return
, on peut spécifier une valeur de retour (= information retournée par la fonction)
Appel de fonction
On fait appel à une fonction en spécifiant simplement son nom, suivi de parenthèses ()
.
ma_fonction()
Si une fonction est définie avec des paramètres, il faudra alors lui transmettre des arguments.
ma_fonction(arg1, arg2)
Quelques exemples
Ces 4 exemples illustrent les différents cas d’usage avec ou sans paramètres et valeurs de retour.
# ❌ pas de "return" / ❌ pas de paramètres
def say_hello1():
print("Hello !")
# ✅ "return" / ❌ pas de paramètres
def say_hello2():
return "Hello !"
# ❌ pas de "return" / ✅ paramètres
def say_hello3(firstname):
print("Hello " + firstname + " !")
# ✅ "return" / ✅ paramètres
def say_hello4(firstname):
return "Hello " + firstname + " !"
# Appels de fonction
say_hello1() # Affiche "Hello !"
print(say_hello2()) # Affiche "Hello !"
say_hello3("Toto") # Affiche "Hello Toto !"
print(say_hello4("Toto")) # Affiche "Hello Toto !"
Cet exemple illustre quant à lui davantage l’intérêt d’une fonction dans un programme.
user1 = {"firstname": "Pierre", "money": 1200}
user2 = {"firstname": "Paul", "money": 100}
user3 = {"firstname": "Jacques", "money": 1600}
def send_money(transmitter, receiver, money):
if transmitter["money"] >= money:
transmitter["money"] -= money
receiver["money"] += money
return "Virement effectué avec succès."
else:
return f"{transmitter['firstname']} n'a pas assez d'argent sur son compte !"
# Appels de fonction
payment1 = send_money(user1, user3, 200) # Renvoie "Virement effectué avec succès."
payment2 = send_money(user2, user3, 200) # Renvoie "Paul n'a pas assez d'argent sur son compte !"
print(payment1)
print(payment2)