Apprendre Python : Algorithmie

Variables, tableaux, conditions, boucles, fonctions... Découvrons la syntaxe de base de Python pour écrire des algorithmes.

Icône de calendrier
Intermédiaire
4 chapitres

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)
copié !
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.

copié !
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.

copié !
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 :

copié !
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] :

copié !
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.

copié !
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.

ValeurIndice PositifIndice Négatif
l0-9
a1-8
C2-7
o3-6
n4-5
s5-4
o6-3
l7-2
e8-1

Le caractère : permet par ailleurs de spécifier des tranches (slices) à extraire d’une séquence comme une liste.

copié !
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 :

copié !
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 :

copié !
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.

copié !
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.

copié !
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 ,
copié !
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 :

  1. La déclaration du dictionnaire
  2. L’initialisation de paires
copié !
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.

copié !
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 :

copié !
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 [].

copié !
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 :

copié !
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é.

copié !
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.

copié !
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.

copié !
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 %.

copié !
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 +.

copié !
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}.

copié !
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érateurUsageDescription
==val1 == val2Teste une égalité stricte (valeur + type)
!=val1 != val2Teste une différence stricte (valeur + type)
<val1 < val2Teste si une valeur est strictement inférieure à une autre
>val1 > val2Teste si une valeur est strictement supérieure à une autre
<=val1 <= val2Teste si une valeur est inférieure ou égale à une autre
>=val1 >= val2Teste 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érateurUsageDescription
andexpr1 and expr2Renvoie True si toutes les comparaisons sont vraies ou False sinon
orexpr1 or expr2Renvoie True si au moins l’une des comparaisons est vraie ou False sinon
notnot exprRenvoie False si une comparaison est vraie ou renvoie True dans le cas contraire
copié !
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 »).

copié !
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.

copié !
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 !

copié !
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.

copié !
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 clauses case.
  • case <expression> : expression à comparer avec la valeur de base.
    1. Si correspondance, exécution d’une instruction
    2. Si non-correspondance, passage au case suivant
  • case _ clause exécutée par défaut si aucune correspondance n’est trouvée avec les clauses case 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 forpour ») 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 pason va de x en x »)
copié !
# 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.
copié !
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 whiletant 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.

copié !
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.

copié !
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 :

  1. Son nom (comme pour les variables, la PEP 8 recommande de privilégier la 🐍 snake_case)
  2. Des instructions
  3. (optionnels) Ses paramètres
  4. (optionnelle) Une valeur de retour (information retournée par la fonction)
Fonction avec nom + instructions
copié !
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
copié !
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 ().

copié !
ma_fonction()

Si une fonction est définie avec des paramètres, il faudra alors lui transmettre des arguments.

copié !
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.

copié !
# ❌ 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.

copié !
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)