Guide pratique Python avec exemples concrets. Fiche mémo, rappels des essentiels (syntaxe, fonction, ...) . Snippets, exemples, démo interactives, ... à suivre
Histoire, philosophie, écosystème
Python est un langage de programmation interprété, polyvalent et très lisible. Créé en 1991 par Guido van Rossum, il est devenu l'un des langages les plus populaires au monde grâce à sa syntaxe claire et sa communauté active.
3 règles d'or pour écrire du code "Pythonique" :
Tapez import this pour voir les 19 aphorismes complets.
Utilisez 4 espaces pour l'indentation, des noms explicites en
snake_case, et aérez votre code.
Ne sacrifiez jamais la lisibilité pour quelques lignes de code en moins. Le code est lu 10x plus qu'il n'est écrit.
Python est utilisé partout, de l'automatisation à l'intelligence artificielle.
| Aspect | Python 2 (❌ Obsolète) | Python 3 (✅ Standard) |
|---|---|---|
print "Hello" |
print("Hello") |
|
| Division entière | 5/2 = 2 |
5/2 = 2.5 (// pour entier) |
| Strings | ASCII par défaut | Unicode (UTF-8) par défaut |
| Support | Fin de vie : 01/01/2020 | Activement maintenu |
2to3.
Déclaration, types, opérateurs
En Python, les variables sont des "étiquettes" qui pointent vers des objets en mémoire. Contrairement à d'autres langages, vous n'avez pas besoin de déclarer le type : Python utilise le typage dynamique. Le type est déterminé automatiquement lors de l'affectation.
Python distingue les types mutables (list, dict, set) des types immuables (int, float, str, tuple). Les objets immuables ne peuvent pas être modifiés après création : toute "modification" crée en réalité un nouvel objet.
Depuis Python 3.5, les type hints permettent d'annoter les types attendus. Ils n'affectent pas l'exécution mais améliorent la lisibilité et permettent aux outils comme mypy de détecter des erreurs.
# Variables (typage dynamique) name = "Alice" # str age = 25 # int price = 19.99 # float is_active = True # bool nothing = None # NoneType # Type hints (Python 3.5+) name: str = "Alice" age: int = 25 prices: list[float] = [9.99, 19.99] user: dict[str, int] = {"age": 25# Vérification de type type(name) # <class 'str'> isinstance(age, int) # True isinstance(age, (int, float)) # True # Conversion (casting) str(42) # "42" int("42") # 42 float("3.14") # 3.14 bool(0) # False list("abc") # ['a', 'b', 'c'] # Opérateurs arithmétiques 5 + 3 # 8 (addition) 5 - 3 # 2 (soustraction) 5 * 3 # 15 (multiplication) 5 / 3 # 1.666... (division) 5 // 3 # 1 (division entière) 5 % 3 # 2 (modulo) 5 ** 3 # 125 (puissance) # Opérateurs de comparaison 5 == 5 # True (égalité) 5 != 3 # True (différent) 5 > 3 # True (supérieur) 5 >= 5 # True (supérieur ou égal) # Opérateurs logiques True and False # False True or False # True not True # False
Affectez une valeur à var_x :
En Python, la variable n'est qu'une étiquette. Elle peut changer de type à tout moment.
| Type | Exemple | Immuable ? | Description |
|---|---|---|---|
int |
42, -10 |
✅ OUI | Entiers (taille illimitée) |
float |
3.14, 1.2e-3 |
✅ OUI | Nombres à virgule flottante |
bool |
True, False |
✅ OUI | Booléens (sous-type de int) |
str |
"Hello" |
✅ OUI | Chaîne Unicode |
NoneType |
None |
✅ OUI | Absence de valeur |
# Assigner ET utiliser dans une expression # Avant : n = len(data) if n > 10: print(f"Trop long: {n}") # Avec Walrus Operator : if (n := len(data)) > 10: print(f"Trop long: {n}") # Utile dans les while while (line := file.readline()): process(line) # Utile dans les list comprehensions filtered = [y for x in data if (y := compute(x)) > 0]
f"Hello {name}" pour l'interpolation de
chaînes. C'est la méthode la plus lisible et performante depuis Python 3.6.Conditions, boucles
Les structures de contrôle permettent de diriger l'exécution du programme. Python utilise l'indentation (espaces) pour délimiter les blocs de code, contrairement aux accolades dans d'autres langages.
La structure if/elif/else permet les branchements conditionnels. L'opérateur
ternaire x if condition else y est une forme compacte pour les cas simples.
Python 3.10 introduit match/case (pattern matching), plus puissant que switch/case
car il peut déconstruire des structures complexes.
# if / elif / else if age < 18: print("Mineur") elif age < 65: print("Adulte") else: print("Senior") # Ternaire status = "Majeur" if age >= 18 else "Mineur" # Match (Python 3.10+) match code: case 200: print("OK") case 404: print("Not Found") case _: print("Error")
# for avec range for i in range(5): print(i) # 0, 1, 2, 3, 4 # for sur itérable for fruit in fruits: print(fruit) # for avec enumerate for i, val in enumerate(lst): print(f"{i}: {val}") # for/else (No Break) for x in data: if x == target: break else: print("Not found") # while while condition: # ... break # sortir continue # suivant
def, lambda, décorateurs
Les fonctions permettent de regrouper du code réutilisable. En Python, elles sont définies avec
def et peuvent retourner une valeur avec return.
*args collecte les arguments positionnels en tuple, **kwargs collecte
les arguments nommés en dictionnaire. Les lambdas sont des fonctions anonymes
sur une ligne.
Les décorateurs (@decorator) modifient le comportement d'une fonction sans changer son code source. Ils sont très utilisés pour le logging, caching, authentification, etc.
# Fonction simple def greet(name): return f"Hello {name}!" # Valeur par défaut def power(base, exp=2): return base ** exp # Type hints def add(a: int, b: int) -> int: return a + b # *args et **kwargs def func(*args, **kwargs): print(args) # tuple print(kwargs) # dict # Lambda double = lambda x: x * 2📦 *ARGS et **KWARGS VisualizerTestez vos arguments (ex:
1, 2, a=3, b="test")*args (Tuple)()Arguments positionnels**kwargs (Dict){}Arguments nommésLe Pattern Décorateur
Décorateur# Décorateur (Wrapper) def decorator(func): def wrapper(*args): print("LOG: Before call") result = func(*args) print("LOG: After call") return result return wrapper @decorator def say_hello(name): print(f"Hello {name}!")Résultat attendugreet("Python") → "Hello Python!" power(2, 8) → 256 double(5) → 10
list, dict, tuple, set
List : séquence ordonnée et modifiable. Tuple : séquence ordonnée et immuable. Set : collection non-ordonnée de valeurs uniques. Dict : paires clé-valeur.
Les comprehensions permettent de créer des collections de manière concise :
[x**2 for x in range(10)] est plus pythonique que la boucle équivalente.
Choisissez le bon type : list pour l'ordre, set pour l'unicité et les opérations ensemblistes, dict pour les associations clé-valeur, tuple pour les données immuables.
| Opération | List (Array) | Set (Hash Map) |
|---|---|---|
Accès index L[i] |
O(1) Très rapide |
❌ Impossible |
Recherche x in L |
O(n) Lent |
O(1) Très rapide |
Ajout append/add |
O(1) |
O(1) |
# Création fruits = ["pomme", "banane", "orange"] nums = list(range(5)) # Accès fruits[0] # "pomme" fruits[-1] # "orange" fruits[1:3] # ["banane", "orange"] # Méthodes fruits.append("kiwi") fruits.insert(0, "mangue") fruits.remove("banane") fruits.pop() fruits.sort() fruits.reverse() # List comprehension squares = [x**2 for x in range(10)] evens = [x for x in nums if x % 2 == 0]
# Création user = { "name": "Alice", "age": 25, "email": "alice@example.com" } # Accès user["name"] # "Alice" user.get("age", 0) # 25 (défaut: 0) # Méthodes user.keys() # clés user.values() # valeurs user.items() # (clé, valeur) user.update({"city": "Paris"}) # Dict comprehension squares = {x: x**2 for x in range(5)}
# Immuable point = (10, 20) x, y = point # unpacking # Named tuple from collections import namedtuple Point = namedtuple('Point', ['x', 'y']) p = Point(10, 20) p.x # 10
# Valeurs uniques s = {1, 2, 3} s.add(4) s.remove(1) # Opérations a | b # union a & b # intersection a - b # différence
Classes, objets, héritage (Thème RPG ⚔️)
La POO permet de structurer le code en créant des modèles (Classes) pour fabriquer des objets concrets. Imaginez un moule à gâteaux (Classe) et les gâteaux produits (Objets).
from abc import ABC, abstractmethod import random # Classe Abstraite (ne peut être instanciée) class Personnage(ABC): def __init__(self, nom, pv): self.nom = nom self.pv = pv # Méthode Abstraite (doit être implémentée par les enfants) @abstractmethod def attaquer(self): pass # Méthode Statique (utilitaire, pas de self) @staticmethod def roll_dice(sides=20): return random.randint(1, sides) class Guerrier(Personnage): def attaquer(self): dmg = Personnage.roll_dice(6) + 2 print(f"{self.nom} frappe ({dmg} dmg) !") class Mage(Personnage): def attaquer(self): dmg = Personnage.roll_dice(10) print(f"{self.nom} lance un sort ({dmg} dmg) !") # p = Personnage("Test") # ERREUR: TypeError (Abstract class) # Polymorphisme groupe = [Guerrier("Conan", 150), Mage("Gandalf", 80)] for h in groupe: h.attaquer() # Chaque classe a sa propre version
La Classe est le plan (moule).
L'Objet est l'instance concrète (gâteau). self référence l'objet
actuel.
class Guerrier(Personnage) : Le Guerrier hérite des
attributs/méthodes du Personnage. Évite la duplication de code.
Protéger les données internes (_protected,
__private). Utilisez des @property pour contrôler l'accès.
Capacité à utiliser une méthode commune (ex: attaquer())
sur différents types d'objets sans connaître leur classe exacte.
@abstractmethod force les enfants à implémenter une
méthode. Empêche d'instancier un modèle incomplet.
@staticmethod appartient à la classe mais n'utilise pas
self. Utile pour des fonctions d'aide ou outils.
Try, Except, Finally (Thème Réacteur ☢️)
Le bloc try/except est le gilet de pare-balles de votre code. Il permet d'intercepter les
erreurs (Exceptions) pour éviter que le programme ne plante brutalement.
Tentez une division dans le cœur du réacteur :
# Structure Complète try: val = int(user_input) res = 100 / val except ValueError: print("Ce n'est pas un nombre !") except ZeroDivisionError: print("Division par zéro interdite !") except Exception as e: print(f"Erreur inconnue : {e}") else: print(f"Résultat : {res}") finally: print("Fin de l'opération.")
except: pass silencieux, c'est le meilleur moyen de cacher des bugs critiques.
Lecture, écriture, JSON
Utilisez toujours with open() pour garantir la fermeture automatique du fichier,
même en cas d'erreur. C'est le pattern "context manager".
Les modes : 'r' lecture, 'w' écriture (écrase), 'a'
append, 'b' binaire. Spécifiez toujours encoding='utf-8' pour le
texte.
pathlib.Path (Python 3.4+) est l'approche moderne pour manipuler les chemins de
manière portable entre Windows/Linux/Mac.
| Mode | Action | Si fichier absent | Si fichier existe |
|---|---|---|---|
'r' |
Lecture | ❌ Erreur | ✅ Lit (début) |
'w' |
Écriture | ✅ Crée | ⚠️ ÉCRASE tout |
'a' |
Ajout | ✅ Crée | ✅ Ajoute (fin) |
'x' |
Création | ✅ Crée | ❌ Erreur |
# Lecture (with = fermeture auto) with open("file.txt", "r", encoding="utf-8") as f: content = f.read() # tout lines = f.readlines() # liste for line in f: # itérer print(line.strip()) # Écriture with open("file.txt", "w") as f: f.write("Hello\n") # Append with open("file.txt", "a") as f: f.write("New line\n") # JSON import json # Sauvegarder with open("data.json", "w") as f: json.dump(data, f, indent=2) # Charger with open("data.json", "r") as f: data = json.load(f) # Pathlib (moderne) from pathlib import Path p = Path("folder/file.txt") p.exists() p.read_text() p.write_text("content")
import csv import pickle # import yaml # pip install pyyaml # CSV Lecture with open("data.csv") as f: reader = csv.reader(f) for row in reader: print(row) # Pickle (Sérialisation binaire objets Python) data = {"temp": 24.5, "hum": 60} with open("data.pkl", "wb") as f: pickle.dump(data, f) with open("data.pkl", "rb") as f: loaded = pickle.load(f)
import, pip, venv
Les modules organisent le code en fichiers réutilisables. Un package est un dossier contenant un
__init__.py. Python cherche les modules dans sys.path.
Utilisez des environnements virtuels (venv) pour isoler les dépendances de chaque projet. C'est une bonne pratique essentielle.
pip est le gestionnaire de packages. requirements.txt liste les
dépendances pour reproduire l'environnement sur une autre machine.
Ne polluez pas votre système ! Créez un dossier venv par projet.
python -m venv venv
.\venv\Scripts\Activate
python3 -m venv venv
source venv/bin/activate
deactivate
Ne polluez pas votre système ! Créez un dossier venv par projet.
python -m venv venv
.\venv\Scripts\Activate
python3 -m venv venv
source venv/bin/activate
deactivate
# Import standard import os import sys import json from datetime import datetime, timedelta from pathlib import Path from typing import List, Dict, Optional # Alias import numpy as np import pandas as pd # Depuis un module local from mypackage.module import function from . import sibling # relatif
# Virtual environment python -m venv venv source venv/bin/activate # Linux/Mac venv\Scripts\activate # Windows # Pip pip install package pip install -r requirements.txt pip freeze > requirements.txt # Exécution python script.py python -m module
Méthodes, Slicing, f-strings
Les chaînes (Strings) sont des séquences immuables de caractères. Vous ne pouvez pas modifier une lettre sur place, mais vous pouvez transformer la chaîne pour en créer une nouvelle.
text = "Python" text[0] # "P" (Premier) text[-1] # "n" (Dernier) text[0:2] # "Py" (Stop exclus) text[2:] # "thon" (Jusqu'à la fin) text[:3] # "Pyt" (Depuis le début) text[::2] # "Pto" (Pas de 2) text[::-1] # "nohtyP" (Inverse)
Retourne True / False
startswith(prefix)endswith(suffix)isdigit() # "123"isalpha() # "abc"isalnum() # "a1"isspace() # " "islower() / isupper()
Sépare ou nettoie
split(sep) # Listesplitlines()partition(sep) # Tuple (av, sep, ap)strip() # Trim espaceslstrip() / rstrip()removeprefix(fix) (3.9+)
Trouve ou compte
find(sub) # Index ou -1index(sub) # Index ou Errorcount(sub) # Nb occurencesreplace(old, new)join(iterable)
Modifie la casse
upper() / lower()title() # "Titulo"capitalize() # "Phrase"swapcase() # aA -> Aacenter(w) / zfill(w)
s = " hello world, python is fun " # Nettoyage et Normalisation clean = s.strip().upper() # "HELLO WORLD, PYTHON IS FUN" # Extraction de mots mots = clean.replace(",", "").split(" ") # ['HELLO', 'WORLD', 'PYTHON', 'IS', 'FUN'] # Reconstruction kebab = "-".join(mots) # "HELLO-WORLD-PYTHON-IS-FUN" # Validation if kebab.startswith("HELLO"): print("Salutations détectées !") # Formatage avancé print("Id".center(10, "=")) # "====Id====" print("42".zfill(5)) # "00042"
Patterns, recherche, validation
Les expressions régulières (regex) sont des séquences de caractères définissant un motif de recherche. Elles sont utilisées pour la validation (emails, téléphones), l'extraction de données, le remplacement de texte et le parsing.
En Python, le module re fournit toutes les fonctionnalités regex. Les patterns sont
généralement définis avec des raw strings (r"pattern") pour éviter les
problèmes d'échappement avec les backslashes.
Les méthodes principales sont match() (début de chaîne), search()
(première occurrence), findall() (toutes les occurrences) et sub()
(remplacement).
import re # Patterns de base pattern = r"\d+" # chiffres pattern = r"[a-zA-Z]+" # lettres pattern = r"\w+" # alphanumérique pattern = r"\s+" # espaces # Méthodes principales re.match(pattern, text) # Début chaîne UNIQUEMENT re.search(pattern, text) # Cherche PARTOUT (1ère occ.) re.findall(pattern, text) # Liste de toutes les occurrences re.finditer(pattern, text) # itérateur re.sub(pattern, repl, text) # remplacer re.split(pattern, text) # découper # Exemple: extraire emails text = "Contact: alice@mail.com, bob@test.fr" emails = re.findall(r"[\w.]+@[\w.]+\.\w+", text) # ['alice@mail.com', 'bob@test.fr'] # Groupes de capture m = re.search(r"(\d{2})/(\d{2})/(\d{4})", "Date: 25/12/2025") m.group(0) # "25/12/2025" (tout) m.group(1) # "25" (jour) m.groups() # ('25', '12', '2025') # Groupes nommés pattern = r"(?P<day>\d{2})/(?P<month>\d{2})/(?P<year>\d{4})" m = re.search(pattern, "25/12/2025") m.group("year") # "2025" # Compilation (performance) regex = re.compile(r"\d+") regex.findall(text)
\d chiffre \D non-chiffre \w mot
\W non-mot \s espace \S non-espace . tout
* 0+ + 1+ ? 0-1 {n}
exactement n {m,n} m à n fois
^ début $ fin \b limite de mot
() capture (?:) non-capture (?P<name>)
nommé | ou
yield, itertools, performances
Les générateurs sont des fonctions qui produisent une séquence de valeurs paresseusement (lazy
evaluation). Au lieu de retourner toutes les valeurs d'un coup, ils les "génèrent" une à une
avec yield.
L'avantage principal est la mémoire : un générateur ne stocke pas toutes les valeurs en mémoire. Idéal pour traiter de gros fichiers ou des séquences infinies.
Les generator expressions sont la version compacte :
(x**2 for x in range(10)) au lieu d'une list comprehension.
# Fonction générateur def countdown(n): while n > 0: yield n n -= 1 for i in countdown(5): print(i) # 5, 4, 3, 2, 1 # Generator expression squares = (x**2 for x in range(1000000)) # économe en mémoire # Générateur infini def infinite_counter(): n = 0 while True: yield n n += 1 # yield from (délégation) def flatten(nested): for item in nested: if isinstance(item, list): yield from flatten(item) else: yield item # itertools from itertools import count, cycle, repeat, chain, islice count(10) # 10, 11, 12, ... cycle([1,2,3]) # 1, 2, 3, 1, 2, 3, ... repeat("A", 5) # A, A, A, A, A chain([1], [2,3]) # 1, 2, 3 islice(gen, 10) # 10 premiers éléments # Interaction (Coroutines avancées) def grep(pattern): print(f"Looking for {pattern}") while True: line = (yield) if pattern in line: print(line) g = grep("python") next(g) # Amorcer g.send("Hello python") # Envoie valeur au yield g.throw(RuntimeError, "Stop") g.close()
async/await, asyncio, concurrence
La programmation asynchrone permet d'exécuter des opérations I/O (réseau, fichiers) de manière non-bloquante. Pendant qu'une tâche attend une réponse, d'autres tâches peuvent s'exécuter.
async def définit une coroutine. await suspend l'exécution jusqu'à ce
que le résultat soit disponible. C'est idéal pour les applications web, les APIs et le scraping.
Le module asyncio gère la boucle d'événements et l'orchestration des tâches
concurrentes.
Choisissez un mode...
import asyncio # Coroutine async def fetch_data(url): print(f"Fetching {url}") await asyncio.sleep(1) # simule I/O return f"Data from {url}" # Exécution séquentielle async def main(): result1 = await fetch_data("url1") result2 = await fetch_data("url2") return [result1, result2] # Exécution parallèle async def main_parallel(): tasks = [ fetch_data("url1"), fetch_data("url2"), fetch_data("url3") ] results = await asyncio.gather(*tasks) return results # Lancer asyncio.run(main()) # Avec timeout try: result = await asyncio.wait_for(fetch_data("url"), timeout=5.0) except asyncio.TimeoutError: print("Timeout!") # HTTP avec aiohttp import aiohttp async def fetch_url(session, url): async with session.get(url) as response: return await response.text()
pytest, unittest, assertions
Les tests unitaires vérifient que chaque composant de votre code fonctionne correctement de manière isolée. Ils permettent de détecter les régressions et de documenter le comportement attendu.
pytest est le framework de test le plus populaire en Python. Il découvre
automatiquement les tests et offre des assertions riches et lisibles.
assert x == yassert x is Trueassert "text" in stringassert x > 0pytest (Run all)pytest -v (Verbose)pytest -k "name" (Filter)pytest -x (Stop on fail)# test_math.py import pytest def add(a, b): return a + b # Test simple def test_add(): assert add(2, 3) == 5 assert add(-1, 1) == 0 # Test d'exception def test_error(): with pytest.raises(ValueError): int("abc") # Paramétrage @pytest.mark.parametrize("a,b,expected", [ (1, 2, 3), (0, 0, 0), (-1, -1, -2), ]) def test_add_param(a, b, expected): assert add(a, b) == expected # Fixture (setup) @pytest.fixture def sample_data(): return [1, 2, 3] def test_with_fixture(sample_data): assert len(sample_data) == 3
import unittest class TestMath(unittest.TestCase): def setUp(self): # Avant chaque test self.data = [1, 2, 3] def test_sum(self): self.assertEqual( sum(self.data), 6 ) def test_len(self): self.assertEqual( len(self.data), 3 ) def test_error(self): with self.assertRaises(IndexError): self.data[10] if __name__ == "__main__": unittest.main()
# Exécuter les tests pytest # tous les tests pytest test_file.py # un fichier pytest -v # verbose pytest -k "test_add" # par nom pytest --cov=mypackage # avec couverture
Built-ins, Dunders, Modules, Keywords
Survolez les termes pour voir leur définition. 💡
print
len
range
type
dir
help
enumerate
zip
map
filter
input
open
abs
round
min
max
sum
sorted
all
any
isinstance
def
class
return
yield
lambda
pass
break
continue
else
elif
try
except
finally
raise
assert
with
import
from
as
global
in
is
not
and
or
__init__
__str__
__repr__
__len__
__getitem__
__setitem__
__delitem__
__iter__
__call__
__eq__
__lt__
__add__
__enter__
__exit__
os
sys
pathlib
json
datetime
re
math
random
collections
itertools
functools
logging
unittest
pickle
threading
asyncio
NumPy, Pandas, Matplotlib
Python est le leader mondial de la Data Science. Voici les 3 piliers de l'écosystème.
| Lib | Objet Principal | Usage |
|---|---|---|
| NumPy | np.array([1,2,3]) |
Calcul mathématique vectorisé |
| Pandas | pd.DataFrame(data) |
Manipulation de tableaux (SQL-like) |
| Matplotlib | plt.plot(x,y) |
Visualisation graphique |
Calcul matriciel haute performance. Les ndarray sont bien plus rapides et économes
que les listes Python.
Manipulation de données structurées (DataFrames). C'est le "Excel programmable" de Python.
> plt.plot(x, y) # Output generated successfully
Linting, Typing, Structure projet
Un code Python professionnel ne se limite pas à la syntaxe. Il respecte des normes strictes pour être maintenable.
my_project/ ├── src/ │ └── main.py # Point d'entrée ├── tests/ │ └── test_main.py # Tests unitaires ├── pyproject.toml # Dépendances (Poetry/UV) ├── README.md # Documentation └── .gitignore # Fichiers à ignorer
# Configuration centralisée (PEP 518) [tool.black] line-length = 88 [tool.ruff] select = ["E", "F", "I"] ignore = ["E501"] [project] name = "my-app" version = "1.0.0" dependencies = [ "fastapi>=0.100", "pydantic>=2.0" ]
Flask vs FastAPI
| Caractéristique | Flask 🌶️ | FastAPI ⚡ |
|---|---|---|
| Architecture | Micro-framework | Moderne & Async |
| Performance | Standard (WSGI) | Très haute (ASGI) |
| Validation | Manuelle | Automatique (Pydantic) |
| Docs API | Manuelle | Auto (Swagger UI) |
from flask import Flask, jsonify app = Flask(__name__) @app.route("/hello/<name>") def hello(name): return jsonify({"msg": f"Hello {name}"}) if __name__ == "__main__": app.run(debug=True)
Simple, mature, idéal pour petits projets et SSR (Jinja2).
from fastapi import FastAPI app = FastAPI() @app.get("/hello/{name}") async def hello(name: str): # Auto-documentation (Swagger UI) return {"msg": f"Hello {name}"} # Run: uvicorn main:app --reload
Rapide, Async natif, Docs auto, Typage strict.