Chapitre 23
Chapitre 23 : Annexes
> **Glossaire, cheat sheets, idioms Python, et erreurs fréquentes** — tout ce qu'il vous faut en référence rapide.
Chapitre 23 — Annexes
Version : 1.0.0
Glossaire (200+ termes), cheat sheets (5), idioms (20), erreurs fréquentes (30).
Table des matières
1. Glossaire
A
ABC (Abstract Base Class) : Classe qui ne peut pas être instanciée directement. Utilisée pour définir une interface. Module abc.
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float: ...
Abstract Syntax Tree (AST) : Représentation arborescente du code source Python. Utilisée par les linters, formatters, et outils d'analyse.
import ast
tree = ast.parse("x = 1 + 2")
Aggregate Root : Entité racine dans DDD qui garantit la cohérence d'un aggregate.
Alembic : Outil de migration de base de données pour SQLAlchemy.
Annotation : Syntaxe pour indiquer le type des variables, paramètres et retours (PEP 484).
AnyIO : Bibliothèque asynchrone indépendante (compatible asyncio et trio).
Argument : Valeur passée à une fonction lors de l'appel.
ASGI : Asynchronous Server Gateway Interface — successeur de WSGI pour les applications async.
asyncio : Bibliothèque standard de programmation asynchrone (PEP 3156).
Awaitable : Objet pouvant être utilisé avec await. Inclut coroutines, Tasks, Futures.
B
Backpressure : Mécanisme de régulation de flux quand un producteur est plus rapide que le consommateur.
Bandit : Analyseur de sécurité statique pour Python.
BaseException : Classe de base de toutes les exceptions. Éviter de la catch directement.
Batteries included : Philosophie Python — la bibliothèque standard couvre de nombreux besoins.
Bytecode : Code intermédiaire compilé par Python avant exécution. Fichiers .pyc.
BLP (Boris L. Pavlov) : Principe de conception objet.
C
Cache : Stockage temporaire pour accélérer les accès répétés.
Celery : Système de tâches asynchrones distribué.
CI/CD : Continuous Integration / Continuous Deployment.
Class variable : Variable partagée par toutes les instances d'une classe.
Clean Architecture : Architecture logicielle qui sépare le code en couches (entités, use cases, adaptateurs, frameworks).
CLI : Command Line Interface. Interface en ligne de commande.
Closure : Fonction qui capture les variables de son environnement de définition.
Comprehension : Syntaxe concise pour créer des listes, dicts, sets.
squares = [x**2 for x in range(10)]
Context Manager : Objet qui gère les ressources via __enter__ et __exit__.
Coroutine : Fonction asynchrone définie avec async def. Retourne un objet coroutine.
Coverage : Mesure du pourcentage de code exécuté par les tests.
CPython : Implémentation de référence de Python (en C).
CQRS : Command Query Responsibility Segregation — séparation des modèles de lecture et d'écriture.
CRUD : Create, Read, Update, Delete — opérations de base sur des données persistées.
CSRF : Cross-Site Request Forgery — attaque qui force un utilisateur à exécuter des actions non désirées.
D
DAG : Directed Acyclic Graph — graphe orienté sans cycle, utilisé par Airflow.
DataClass : Décorateur qui génère automatiquement __init__, __repr__, __eq__, etc.
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
Deadlock : Situation où deux threads s'attendent mutuellement, bloquant l'exécution.
Decorator : Fonction qui modifie le comportement d'une autre fonction.
Dependency Injection : Pattern où les dépendances sont fournies de l'extérieur plutôt que créées en interne.
Descriptor : Objet qui implémente __get__, __set__, ou __delete__ pour contrôler l'accès aux attributs.
Docker : Plateforme de conteneurisation.
Docstring : Chaîne de documentation en début de module, classe, ou fonction.
DOM : Document Object Model — représentation en mémoire d'un document XML/HTML.
DRF : Django REST Framework.
DRY : Don't Repeat Yourself — principe d'éviter la duplication de code.
DTO : Data Transfer Object — objet pour transporter des données entre couches.
Duck Typing : "Si ça marche comme un canard et que ça cancane comme un canard, alors c'est un canard." Python privilégie le comportement sur le type.
E
EAFP : Easier to Ask for Forgiveness than Permission. Style Python : essayer, et gérer l'erreur si elle arrive.
try:
value = my_dict[key]
except KeyError:
value = default
Encapsulation : Principe de cacher l'implémentation interne d'un objet.
Entry point : Point d'entrée d'une application (ex: app = FastAPI()).
Enum : Type énuméré (PEP 435). Ensemble de valeurs nommées.
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
Event Loop : Boucle d'événements qui exécute les coroutines et callbacks asynchrones.
Exception : Événement qui interrompt le flux normal d'exécution.
F
F-string : Chaîne formatée (PEP 498). f"Hello {name}".
Factory : Pattern de création d'objets.
FastAPI : Framework web moderne, haut-performant, basé sur Starlette et Pydantic.
Fixture : Fonction pytest qui fournit un contexte reproductible pour les tests.
Flake8 : Linter Python (regroupe PyFlakes, pycodestyle, McCabe).
Fluent interface : Style d'API où les méthodes retournent self pour le chaînage.
Free-threaded mode : Mode Python 3.13 où le GIL est désactivé.
frozenset : Version immuable de set.
Future : Objet qui représente un résultat asynchrone pas encore disponible.
G
Garbage Collector : Collecteur de déchets qui libère la mémoire des objets non utilisés.
Generics : Types paramétrés (PEP 484). list[int], dict[str, float].
Generator : Fonction qui utilise yield pour produire une séquence de valeurs paresseuse.
GIL : Global Interpreter Lock — mutex qui protège l'accès aux objets Python.
Global Interpreter Lock : Voir GIL.
GroupBy : Opération pandas pour regrouper des données.
Gunicorn : Serveur WSGI pour applications Python.
H
Hashable : Objet qui peut être utilisé comme clé de dictionnaire. Doit implémenter __hash__.
HTTPX : Client HTTP asynchrone moderne pour Python.
Hypothesis : Bibliothèque de property-based testing.
I
I/O bound : Tâche limitée par les entrées/sorties (réseau, disque).
id() : Fonction qui retourne l'identifiant mémoire d'un objet.
Idempotent : Opération qui produit le même résultat quand elle est exécutée plusieurs fois.
Immutable : Non modifiable après création. Ex: tuple, str, int, frozenset.
Import : Mécanisme pour charger des modules et packages.
Injection de dépendances : Voir Dependency Injection.
isinstance() : Fonction qui vérifie si un objet est une instance d'une classe.
Iterable : Objet qui implémente __iter__ ou __getitem__.
Iterator : Objet qui implémente __iter__ et __next__.
J
Jinja2 : Moteur de templates pour Python.
JIT : Just-In-Time compilation — compilation à l'exécution pour améliorer les performances.
JSON : JavaScript Object Notation — format d'échange de données léger.
JWT : JSON Web Token — format de token d'authentification.
K
kwargs : Keyword arguments — dictionnaire des arguments nommés (**kwargs).
L
Lambda : Fonction anonyme à une seule expression. lambda x: x * 2.
LBYL : Look Before You Leap. Style opposé à EAFP : vérifier avant d'agir.
List comprehension : Compréhension de liste (voir Comprehension).
Linter : Outil d'analyse statique qui détecte les erreurs potentielles.
LRU Cache : Least Recently Used cache — évince les éléments les moins récemment utilisés.
M
MagicMock : Classe de mock automatique dans unittest.mock.
Metaclass : Classe de classe. Personnalise la création des classes.
Middleware : Logiciel qui agit comme pont entre l'application et le serveur.
Migration : Changement de schéma de base de données (via Alembic).
Mixin : Classe qui fournit des méthodes supplémentaires sans être utilisée seule.
Mock : Objet simulé pour les tests, qui imite le comportement d'un objet réel.
Module : Fichier .py contenant du code Python.
Monkey Patching : Modification dynamique de classes ou modules à l'exécution.
MRO : Method Resolution Order — ordre de résolution des méthodes dans l'héritage multiple.
Mutable : Modifiable après création. Ex: list, dict, set.
mypy : Vérificateur de types statique optionnel pour Python.
N
Namespace : Espace de noms qui mappe les noms aux objets.
Name mangling : Transformation des noms d'attributs privés (__attr → _Class__attr).
NaN : Not a Number — valeur manquante dans pandas/numpy.
numpy : Bibliothèque de calcul numérique en Python.
O
Object : Instance d'une classe. Base de tous les types en Python.
OOP : Object-Oriented Programming.
OpenAPI : Spécification pour les API REST (anciennement Swagger).
Operator overloading : Surcharge d'opérateurs via des méthodes spéciales (__add__, __eq__, etc.).
ORM : Object-Relational Mapping — mapping objet-relationnel.
Overfitting : Modèle qui apprend trop bien les données d'entraînement mais généralise mal.
P
Package : Dossier contenant __init__.py et des modules Python.
pandas : Bibliothèque de manipulation et analyse de données.
Parameter : Variable définie dans la signature d'une fonction.
Parametrize : Décorateur pytest pour exécuter un test avec plusieurs jeux de données.
PEP : Python Enhancement Proposal — proposition d'amélioration de Python.
Pipeline : Enchaînement d'étapes de traitement. Utilisé par scikit-learn, pandas, CI/CD.
Polymorphism : Capacité d'un objet à se comporter différemment selon son type.
Property : Attribut contrôlé par des getters/setters avec @property.
Protocol : Classe qui définit une interface pour le duck typing statique (PEP 544).
PSF : Python Software Foundation.
Pydantic : Bibliothèque de validation de données basée sur les type hints.
PyPI : Python Package Index — dépôt officiel des packages Python.
pytest : Framework de test pour Python.
Pythonic : Code qui suit les conventions et idiomes de Python.
Q-R
Query : Requête (base de données, API).
Race condition : Situation où le comportement dépend de l'ordre d'exécution non déterministe.
Recursion : Fonction qui s'appelle elle-même.
Reference counting : Comptage de références pour la gestion mémoire.
Repository : Pattern qui abstrait la persistance des données.
REST : Representational State Transfer — style d'architecture pour les API web.
ruff : Linter et formatter Python ultra-rapide écrit en Rust.
S
scikit-learn : Bibliothèque de machine learning pour Python.
Scope : Portée d'une variable. LEGB : Local, Enclosing, Global, Built-in.
Sentinel : Valeur spéciale utilisée comme marqueur (ex: object() pour détecter "non fourni").
Serialization : Conversion d'un objet en format transportable (JSON, pickle).
Set : Collection non ordonnée d'éléments uniques.
Singleton : Pattern où une classe n'a qu'une seule instance.
Slice : Syntaxe pour extraire une partie d'une séquence. seq[start:stop:step].
SOLID : Cinq principes de conception orientée objet.
SQLAlchemy : ORM et toolkit SQL pour Python.
Starlette : Framework ASGI léger, base de FastAPI.
Static method : Méthode qui n'accède ni à l'instance ni à la classe (@staticmethod).
Syn责任 : Blocage. Opération synchrone = bloquante.
T
Task : Coroutine en cours d'exécution gérée par l'event loop.
Thread : Unité d'exécution légère. Limitée par le GIL pour le CPU.
Timeout : Limite de temps pour une opération.
Tri : Opération de tri. sorted(), list.sort().
tuple : Séquence immuable.
Type hint : Annotation de type optionnelle. name: str = "World".
Typer : Bibliothèque CLI basée sur les type hints.
U-Z
UML : Unified Modeling Language — langage de modélisation.
Unit of Work : Pattern qui maintient la cohérence des changements dans un contexte transactionnel.
Uvicorn : Serveur ASGI pour applications async Python.
Virtual environment : Environnement Python isolé.
WebSocket : Protocole de communication bidirectionnelle temps réel.
WSGI : Web Server Gateway Interface — interface standard pour les applications web synchrones.
WSGI : Voir WSGI.
XSS : Cross-Site Scripting — injection de scripts malveillants.
Yield : Mot-clé qui transforme une fonction en générateur.
Zen of Python : 19 principes directeurs de Python. import this.
Zip : Fonction qui agrège des itérables élément par élément.
2. Cheat Sheets
Cheat Sheet — pandas
import pandas as pd
import numpy as np
# Création
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
s = pd.Series([1, 2, 3], name='col')
# Lecture/Écriture
df.to_csv('file.csv', index=False)
df.to_parquet('file.parquet')
df = pd.read_csv('file.csv')
df = pd.read_parquet('file.parquet')
# Inspection
df.head(10) # Premières lignes
df.info() # Types, mémoire
df.describe() # Statistiques
df.shape # Dimensions (rows, cols)
df.columns # Noms de colonnes
df.dtypes # Types par colonne
# Sélection
df['col'] # Une colonne → Series
df[['col1', 'col2']] # Plusieurs colonnes → DataFrame
df.loc[0] # Par label (ligne 0)
df.iloc[0] # Par position
df.query('A > 2') # Avec expression
df.filter(like='pattern') # Filtre les colonnes par nom
# Nettoyage
df.dropna() # Supprime NaN
df.fillna(0) # Remplace NaN
df.drop_duplicates() # Supprime doublons
df.rename(columns={'A': 'new_A'})
df['A'].astype(float) # Convertit le type
# GroupBy
df.groupby('A').sum()
df.groupby('A').agg({'B': 'sum', 'C': 'mean'})
df.groupby('A').transform('rank')
# Merge
pd.merge(df1, df2, on='key', how='left')
pd.concat([df1, df2], axis=0)
# Time Series
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)
df.resample('D').mean() # Rééchantillonage
df.rolling(7).mean() # Fenêtre glissante
df.shift(1) # Décalage (lag)
# Apply / Map
df['A'].apply(lambda x: x * 2)
df['category'] = df['A'].map({1: 'low', 2: 'high'})
# Pivot
pd.pivot_table(df, values='sales', index='region', columns='year')
df.melt(id_vars=['id'], var_name='year', value_name='sales')
Cheat Sheet — FastAPI
from fastapi import FastAPI, HTTPException, Depends, Query, WebSocket
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel, Field
from typing import Annotated
app = FastAPI(title="My API", version="1.0.0")
# --- Modèles Pydantic ---
class Item(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
price: float = Field(..., gt=0)
in_stock: bool = True
class ItemResponse(Item):
id: int
# --- Routes CRUD ---
@app.post("/items", response_model=ItemResponse, status_code=201)
async def create_item(item: Item) -> ItemResponse:
...
@app.get("/items")
async def list_items(
page: int = Query(1, ge=1),
size: int = Query(20, ge=1, le=100),
) -> list[ItemResponse]:
...
@app.get("/items/{item_id}")
async def get_item(item_id: int) -> ItemResponse:
if item_id not in items:
raise HTTPException(status_code=404, detail="Item not found")
return items[item_id]
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item) -> ItemResponse:
...
@app.delete("/items/{item_id}", status_code=204)
async def delete_item(item_id: int) -> None:
...
# --- Dépendances ---
async def pagination(
page: int = Query(1, ge=1),
size: int = Query(20, ge=1, le=100),
) -> tuple[int, int]:
return (page, size)
@app.get("/paginated")
async def paginated_endpoint(
pag: tuple[int, int] = Depends(pagination),
) -> dict:
page, size = pag
return {"page": page, "size": size}
# --- Sécurité ---
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login")
@app.post("/auth/login")
async def login(username: str, password: str) -> dict:
...
@app.get("/protected")
async def protected_route(token: str = Depends(oauth2_scheme)) -> dict:
return {"token": token}
# --- WebSocket ---
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket) -> None:
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Echo: {data}")
# --- Configuration ---
@app.on_event("startup")
async def startup() -> None:
# Initialiser DB, cache, etc.
pass
@app.on_event("shutdown")
async def shutdown() -> None:
# Fermer connexions
pass
# --- Healthcheck ---
@app.get("/health")
async def health() -> dict:
return {"status": "ok"}
Cheat Sheet — pytest
import pytest
from unittest.mock import Mock, patch, MagicMock
# --- Fixtures ---
@pytest.fixture
def sample_data() -> dict:
return {"key": "value"}
@pytest.fixture(scope="module")
def heavy_resource():
# setup
resource = create_expensive_resource()
yield resource
# teardown
resource.close()
@pytest.fixture(autouse=True)
def auto_fixture():
"""Appliqué à tous les tests du fichier"""
pass
# --- Tests ---
def test_basic(sample_data: dict) -> None:
assert sample_data["key"] == "value"
def test_exception() -> None:
with pytest.raises(ValueError, match="invalid"):
raise ValueError("invalid value")
def test_approx() -> None:
assert 0.1 + 0.2 == pytest.approx(0.3)
# --- Paramétrage ---
@pytest.mark.parametrize("input_val,expected", [
(1, 2),
(2, 4),
(3, 6),
], ids=["one", "two", "three"])
def test_double(input_val: int, expected: int) -> None:
assert input_val * 2 == expected
# --- Mocking ---
def test_with_mock() -> None:
mock = MagicMock()
mock.get_data.return_value = {"result": 42}
assert mock.get_data() == {"result": 42}
@patch("module.requests.get")
def test_api_call(mock_get: MagicMock) -> None:
mock_get.return_value.json.return_value = {"ok": True}
# Le code qui appelle requests.get utilise le mock
...
# --- Marks ---
@pytest.mark.slow
def test_slow_operation() -> None:
...
@pytest.mark.skip(reason="Not implemented yet")
def test_future() -> None:
...
@pytest.mark.skipif(sys.version_info < (3, 12), reason="Requires 3.12+")
def test_python_version() -> None:
...
# --- Fixtures avancées ---
@pytest.fixture
def mock_db(mocker):
return mocker.patch("module.Database")
@pytest.mark.asyncio
async def test_async_function() -> None:
result = await async_function()
assert result == "expected"
# --- Temporary files ---
def test_temp_file(tmp_path) -> None:
d = tmp_path / "subdir"
d.mkdir()
f = d / "test.txt"
f.write_text("hello")
assert f.read_text() == "hello"
# --- Capture stdout ---
def test_output(capsys) -> None:
print("Hello")
captured = capsys.readouterr()
assert captured.out == "Hello\n"
Cheat Sheet — SQLAlchemy 2.0
from sqlalchemy import create_engine, text, select, func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy.orm import relationship, Session, sessionmaker
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
# --- Configuration ---
engine = create_engine("postgresql+psycopg://user:pass@localhost/db")
async_engine = create_async_engine(
"postgresql+asyncpg://user:pass@localhost/db"
)
SessionLocal = sessionmaker(engine, class_=Session)
AsyncSessionLocal = sessionmaker(async_engine, class_=AsyncSession)
# --- Modèles ---
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(unique=True)
email: Mapped[str]
posts: Mapped[list["Post"]] = relationship(back_populates="author")
class Post(Base):
__tablename__ = "posts"
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
body: Mapped[str]
author_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
author: Mapped["User"] = relationship(back_populates="posts")
# --- CRUD (sync) ---
with Session(engine) as session:
# Create
user = User(name="Alice", email="alice@example.com")
session.add(user)
session.commit()
# Read
user = session.get(User, 1)
users = session.scalars(select(User)).all()
user = session.scalar(
select(User).where(User.name == "Alice")
)
# Update
user.name = "Alicia"
session.commit()
# Delete
session.delete(user)
session.commit()
# --- CRUD (async) ---
async with AsyncSession(async_engine) as session:
user = User(name="Bob", email="bob@example.com")
session.add(user)
await session.commit()
result = await session.execute(
select(User).where(User.name == "Bob")
)
user = result.scalar_one()
# --- Relations ---
with Session(engine) as session:
user = session.get(User, 1)
print(user.posts) # Accès lazy
# Eager loading
from sqlalchemy.orm import joinedload
user = session.scalar(
select(User)
.options(joinedload(User.posts))
.where(User.id == 1)
)
# --- Core (sans ORM) ---
with engine.connect() as conn:
result = conn.execute(text("SELECT * FROM users"))
for row in result:
print(row.name)
conn.execute(
text("INSERT INTO users (name) VALUES (:name)"),
[{"name": "Charlie"}, {"name": "Dave"}],
)
conn.commit()
# --- Migrations (Alembic) ---
# alembic init alembic
# alembic revision --autogenerate -m "create users"
# alembic upgrade head
Cheat Sheet — asyncio
import asyncio
from asyncio import Task, Future, Queue, Event
# --- Création et exécution ---
async def main():
result = await async_function()
return result
asyncio.run(main())
# --- Tâches ---
async def worker(name: str, delay: float) -> str:
await asyncio.sleep(delay)
return f"Worker {name} done"
async def main():
task = asyncio.create_task(worker("A", 1.0))
result = await task
# Tâches en concurrence
tasks = [asyncio.create_task(worker(n, d)) for n, d in [("A",1), ("B",2)]]
results = await asyncio.gather(*tasks)
# --- TaskGroup (3.11+) ---
async def main():
async with asyncio.TaskGroup() as tg:
t1 = tg.create_task(worker("X", 1))
t2 = tg.create_task(worker("Y", 2))
# Toutes les tâches sont terminées ici
# --- Timeout ---
async def main():
try:
async with asyncio.timeout(5):
result = await slow_operation()
except TimeoutError:
result = fallback
# --- Queue producteur/consommateur ---
async def producer(queue: asyncio.Queue, n: int) -> None:
for i in range(n):
await queue.put(i)
await asyncio.sleep(0.1)
await queue.put(None) # Sentinel
async def consumer(queue: asyncio.Queue) -> None:
while True:
item = await queue.get()
if item is None:
queue.task_done()
break
print(f"Processed {item}")
queue.task_done()
async def main():
queue = asyncio.Queue(maxsize=10)
async with asyncio.TaskGroup() as tg:
tg.create_task(producer(queue, 5))
tg.create_task(consumer(queue))
# --- Synchronisation ---
lock = asyncio.Lock()
event = asyncio.Event()
semaphore = asyncio.Semaphore(10)
async def with_lock():
async with lock:
# Section critique
pass
# --- Sous-processus ---
async def run_cmd():
proc = await asyncio.create_subprocess_shell(
"echo hello",
stdout=asyncio.subprocess.PIPE,
)
stdout, _ = await proc.communicate()
return stdout.decode()
# --- Files ---
async def read_file():
loop = asyncio.get_running_loop()
with open("file.txt") as f:
return await loop.run_in_executor(None, f.read)
# --- AnyIO (compatible asyncio+trio) ---
import anyio
async def anyio_main():
async with anyio.create_task_group() as tg:
tg.start_soon(worker, "A", 1)
tg.start_soon(worker, "B", 2)
anyio.run(anyio_main)
3. Python Idioms
IDIOM 1 : Swap de variables
# 🚫 Mauvais
temp = a
a = b
b = temp
# ✅ Pythonic
a, b = b, a
IDIOM 2 : Test de vérité
# 🚫 Mauvais
if len(items) > 0: ...
if value == True: ...
if bool(x) == True: ...
# ✅ Pythonic
if items: ...
if value: ...
if x: ...
IDIOM 3 : Itération avec index
# 🚫 Mauvais
for i in range(len(items)):
print(items[i])
# ✅ Pythonic
for i, item in enumerate(items):
print(i, item)
IDIOM 4 : Itération sur deux listes
# 🚫 Mauvais
for i in range(len(names)):
print(names[i], ages[i])
# ✅ Pythonic
for name, age in zip(names, ages):
print(name, age)
IDIOM 5 : Construction de chaîne
# 🚫 Mauvais
result = ""
for s in strings:
result += s
# ✅ Pythonic
result = "".join(strings)
IDIOM 6 : Valeur par défaut
# 🚫 Mauvais
if key in d:
value = d[key]
else:
value = default
# ✅ Pythonic
value = d.get(key, default)
IDIOM 7 : Vérification d'appartenance
# 🚫 Mauvais
if d.get(key) is not None: ...
if type(x) == int: ...
# ✅ Pythonic
if key in d: ...
if isinstance(x, int): ...
IDIOM 8 : Retour conditionnel
# 🚫 Mauvais
if condition:
return True
else:
return False
# ✅ Pythonic
return condition
# ou
return True if condition else False
IDIOM 9 : Filtrage de liste
# 🚫 Mauvais
result = []
for x in items:
if x > 0:
result.append(x)
# ✅ Pythonic
result = [x for x in items if x > 0]
IDIOM 10 : Ouverture de fichier
# 🚫 Mauvais
f = open("file.txt")
data = f.read()
f.close()
# ✅ Pythonic
with open("file.txt") as f:
data = f.read()
# Le fichier est fermé automatiquement
IDIOM 11 : Opération ternaire
# ✅ Pythonic
status = "adult" if age >= 18 else "minor"
IDIOM 12 : Déballage de tuple
# ✅ Pythonic
name, age, city = ("Alice", 30, "Paris")
first, *middle, last = [1, 2, 3, 4, 5]
# first=1, middle=[2,3,4], last=5
IDIOM 13 : Négation d'appartenance
# ✅ Pythonic
if x not in items: ...
# au lieu de : if not x in items: ...
IDIOM 14 : Défense contre None
# ✅ Pythonic
result = maybe_none or default
IDIOM 15 : Itération avec condition
# ✅ Pythonic
all(x > 0 for x in items) # True si tous > 0
any(x > 0 for x in items) # True si un > 0
IDIOM 16 : Transposition matrice
# ✅ Pythonic
matrix = [[1, 2], [3, 4], [5, 6]]
transposed = list(zip(*matrix))
# [(1, 3, 5), (2, 4, 6)]
IDIOM 17 : Applatissement de liste
# ✅ Pythonic
nested = [[1, 2], [3, 4], [5]]
flat = [x for sub in nested for x in sub]
# [1, 2, 3, 4, 5]
IDIOM 18 : Comptage d'occurrences
# 🚫 Mauvais
counts = {}
for x in items:
if x in counts:
counts[x] += 1
else:
counts[x] = 1
# ✅ Pythonic (Python 3.10+)
from collections import Counter
counts = Counter(items)
IDIOM 19 : Dataclasses pour les données simples
# 🚫 Mauvais
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
# ✅ Pythonic
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
IDIOM 20 : Walrus operator (:=)
# ✅ Pythonic (3.8+)
if (n := len(items)) > 10:
print(f"Too many: {n}")
# vs
n = len(items)
if n > 10:
print(f"Too many: {n}")
4. Common Mistakes
MISTAKE 1 : Utiliser is pour comparer des nombres
# 🚫 Mauvais
x = 256
y = 256
print(x is y) # True (cache Python, mais pas garanti)
# ✅ Correct
print(x == y) # True (toujours correct)
MISTAKE 2 : Mutables comme paramètres par défaut
# 🚫 Mauvais
def add_item(item, lst=[]):
lst.append(item)
return lst
# ✅ Correct
def add_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
MISTAKE 3 : Modifier une liste en l'itérant
# 🚫 Mauvais
for item in lst:
if condition(item):
lst.remove(item) # Bug : saute des éléments
# ✅ Correct
lst = [item for item in lst if not condition(item)]
MISTAKE 4 : Confondre == et is pour les chaînes
# 🚫 Mauvais
if status is "ok": ...
# ✅ Correct
if status == "ok": ...
MISTAKE 5 : Ignorer les exceptions
# 🚫 Mauvais
try:
risky_operation()
except Exception: # Trop large
pass
# ✅ Correct
try:
risky_operation()
except SpecificError as e:
logger.error("Opération échouée", exc_info=e)
raise
MISTAKE 6 : Ne pas fermer les fichiers
# 🚫 Mauvais
f = open("file.txt")
data = f.read()
# f n'est pas fermé
# ✅ Correct
with open("file.txt") as f:
data = f.read()
MISTAKE 7 : Shadowing de builtins
# 🚫 Mauvais
list = [1, 2, 3] # Écrase la fonction builtin list()
id = 42 # Écrase la fonction id()
# ✅ Correct
my_list = [1, 2, 3]
item_id = 42
MISTAKE 8 : Type checking inutile
# 🚫 Mauvais
if type(x) == int: ...
# ✅ Correct (duck typing)
try:
result = x + 1
except TypeError:
pass
MISTAKE 9 : Chaînes de concaténation dans une boucle
# 🚫 Mauvais (O(n²))
result = ""
for s in many_strings:
result += s
# ✅ Correct (O(n))
result = "".join(many_strings)
MISTAKE 10 : Ne pas utiliser enumerate
# 🚫 Mauvais
for i in range(len(items)):
print(i, items[i])
# ✅ Correct
for i, item in enumerate(items):
print(i, item)
MISTAKE 11 : Clé de dict mutable
# 🚫 Mauvais
d = {}
d[[1, 2]] = "value" # TypeError: unhashable type: 'list'
# ✅ Correct
d[(1, 2)] = "value"
MISTAKE 12 : Référence circulaire
# 🚫 Mauvais
class A:
def __init__(self):
self.other = B(self)
class B:
def __init__(self, a):
self.other = a
# Cause des problèmes de garbage collection
MISTAKE 13 : Utiliser time.time() pour mesurer
# 🚫 Mauvais
start = time.time()
# ... opération ...
end = time.time()
# ✅ Correct
start = time.perf_counter()
# ... opération ...
end = time.perf_counter()
MISTAKE 14 : Comparer des floats avec ==
# 🚫 Mauvais
if 0.1 + 0.2 == 0.3: ... # False !!
# ✅ Correct
if abs((0.1 + 0.2) - 0.3) < 1e-9: ...
# ou
import math
if math.isclose(0.1 + 0.2, 0.3): ...
MISTAKE 15 : Oublier return dans une fonction
# 🚫 Mauvais
def get_value():
value = compute() # Pas de return
result = get_value() # None
# ✅ Correct
def get_value():
return compute()
MISTAKE 16 : Modifier une boucle avec remove
# 🚫 Mauvais
items = [1, 2, 3, 4]
for item in items:
if item % 2 == 0:
items.remove(item) # items = [1, 3, 4]
# ✅ Correct
items = [item for item in items if item % 2 != 0]
MISTAKE 17 : Ne pas utiliser __slots__ pour des millions d'objets
# 🚫 Mauvais
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
# Chaque instance → dict (coûteux)
# ✅ Correct
class Point:
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
# Pas de dict, mémoire réduite
MISTAKE 18 : except: nu
# 🚫 Mauvais
try:
something()
except:
handle()
# ✅ Correct
try:
something()
except Exception as e:
handle(e)
MISTAKE 19 : Global mutable
# 🚫 Mauvais
MODULE_CACHE = {}
def process(data):
MODULE_CACHE[data.id] = data
# Effet de bord dangereux
# ✅ Correct (passer en paramètre)
def process(data, cache):
cache[data.id] = data
MISTAKE 20 : Confusion entre extend et append
# 🚫 Mauvais
a = [1, 2]
a.append([3, 4]) # a = [1, 2, [3, 4]]
# ✅ Correct
a = [1, 2]
a.extend([3, 4]) # a = [1, 2, 3, 4]
MISTAKE 21 : Utiliser import *
# 🚫 Mauvais
from module import *
# Pollution du namespace, conflits potentiels
# ✅ Correct
from module import specific_function
MISTAKE 22 : Ne pas gérer les timezones
# 🚫 Mauvais
from datetime import datetime
now = datetime.now() # Naive datetime
# ✅ Correct
from datetime import datetime, timezone
now = datetime.now(timezone.utc)
MISTAKE 23 : Multiplier les appels à len()
# 🚫 Mauvais
for i in range(len(items)):
if i < len(items) - 1:
process(items[i], items[i + 1])
# ✅ Correct
for a, b in zip(items, items[1:]):
process(a, b)
MISTAKE 24 : Utiliser eval() ou exec()
# 🚫 Mauvais (injection possible)
eval(user_input)
# ✅ Correct
ast.literal_eval(user_input) # Plus sûr
MISTAKE 25 : Oublier le self dans les méthodes
# 🚫 Mauvais
class MyClass:
def method():
print("Hello")
obj = MyClass()
obj.method() # TypeError: method() takes 0 positional arguments but 1 was given
MISTAKE 26 : Copier une liste avec =
# 🚫 Mauvais
original = [1, 2, 3]
copy = original # Référence, pas une copie
# ✅ Correct
copy = original.copy()
copy = list(original)
copy = original[:]
MISTAKE 27 : Sortie de contexte anticipée dans un générateur
# 🚫 Mauvais
def gen():
with open("file.txt") as f:
yield f.read()
# Le fichier est fermé après le premier next()
MISTAKE 28 : Appeler super().__init__ dans l'ordre MRO
# 🚫 Mauvais
class C(A, B):
def __init__(self):
A.__init__(self)
B.__init__(self)
# ✅ Correct
class C(A, B):
def __init__(self):
super().__init__() # MRO automatique
MISTAKE 29 : Oublier await sur une coroutine
# 🚫 Mauvais
async def main():
result = async_function()
# Retourne une coroutine, pas le résultat
# ✅ Correct
async def main():
result = await async_function()
MISTAKE 30 : Bloquer l'event loop
# 🚫 Mauvais
async def handler():
time.sleep(1) # Bloque tout l'event loop
# ✅ Correct
async def handler():
await asyncio.sleep(1) # Libère l'event loop
Prochain chapitre : 24-Tendances →
Les tendances actuelles et futures de l'écosystème Python.