Communitygithub.com

python-patterns

Idiomes Pythoniques, normes PEP 8, indications de type et meilleures pratiques pour construire des applications Python robustes, efficaces et maintenables. À utiliser lors de l'écriture ou de la révision de code Python lorsque la structure idiomatique, le typage ou la conformité PEP 8 est en question.

Qu'est-ce que python-patterns ?

Ce skill fournit des patrons et bonnes pratiques idiomatiques Python, basés sur PEP 8, les indications de type et les normes de la communauté. Il couvre la lisibilité, le principe EAFP (Easier to Ask Forgiveness Than Permission), la gestion des erreurs, les context managers, les compréhensions, les générateurs, les classes de données, les décorateurs et les modèles de concurrence. L'objectif est d'aider les développeurs à écrire un code plus robuste, efficace et maintenable, que ce soit pour la création, la révision ou le refactoring. Le skill détaille aussi l'organisation des packages, les importations et l'optimisation mémoire/performances, avec des exemples concrets en Python 3.9+. Il est conçu pour des agents IA comme Claude Code, Cursor ou Codex, leur fournissant des directives précises pour générer ou analyser du code Python.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/python-patterns

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Patrons de développement Python

Patrons et bonnes pratiques Python idiomatiques pour construire des applications robustes, efficaces et maintenables.

Quand activer

  • Écrire du nouveau code Python
  • Réviser du code Python
  • Refactoriser du code Python existant
  • Concevoir des paquets/modules Python

Principes fondamentaux

1. La lisibilité compte

Python privilégie la lisibilité. Le code doit être évident et facile à comprendre.

# Bien : Clair et lisible
def get_active_users(users: list[User]) -> list[User]:
    """Retourne uniquement les utilisateurs actifs de la liste fournie."""
    return [user for user in users if user.is_active]


# Mal : Astucieux mais confus
def get_active_users(u):
    return [x for x in u if x.a]

2. L'explicite est mieux que l'implicite

Évitez la magie ; soyez clair sur ce que fait votre code.

# Bien : Configuration explicite
import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

# Mal : Effets secondaires cachés
import some_module
some_module.setup()  # Qu'est-ce que ça fait ?

3. EAFP - Il est plus facile de demander pardon que la permission

Python préfère la gestion des exceptions à la vérification des conditions.

# Bien : Style EAFP
def get_value(dictionary: dict, key: str, default_value: Any = None) -> Any:
    try:
        return dictionary[key]
    except KeyError:
        return default_value

# Mal : Style LBYL (Regarde avant de sauter)
def get_value(dictionary: dict, key: str, default_value: Any = None) -> Any:
    if key in dictionary:
        return dictionary[key]
    else:
        return default_value

Indications de type

Annotations de type de base

from typing import Optional, List, Dict, Any

def process_user(
    user_id: str,
    data: Dict[str, Any],
    active: bool = True
) -> Optional[User]:
    """Traite un utilisateur et retourne l'utilisateur mis à jour ou None."""
    if not active:
        return None
    return User(user_id, data)

Indications de type modernes (Python 3.9+)

# Python 3.9+ - Utilisez les types natifs
def process_items(items: list[str]) -> dict[str, int]:
    return {item: len(item) for item in items}

# Python 3.8 et antérieur - Utilisez le module typing
from typing import List, Dict

def process_items(items: List[str]) -> Dict[str, int]:
    return {item: len(item) for item in items}

Alias de type et TypeVar

from typing import TypeVar, Union

# Alias de type pour types complexes
JSON = Union[dict[str, Any], list[Any], str, int, float, bool, None]

def parse_json(data: str) -> JSON:
    return json.loads(data)

# Types génériques
T = TypeVar('T')

def first(items: list[T]) -> T | None:
    """Retourne le premier élément ou None si la liste est vide."""
    return items[0] if items else None

Duck typing basé sur les protocoles

from typing import Protocol

class Renderable(Protocol):
    def render(self) -> str:
        """Convertit l'objet en chaîne de caractères."""

def render_all(items: list[Renderable]) -> str:
    """Convertit tous les éléments qui implémentent le protocole Renderable."""
    return "\n".join(item.render() for item in items)

Patrons de gestion des erreurs

Gestion spécifique des exceptions

# Bien : Attraper des exceptions spécifiques
def load_config(path: str) -> Config:
    try:
        with open(path) as f:
            return Config.from_json(f.read())
    except FileNotFoundError as e:
        raise ConfigError(f"Fichier de configuration introuvable : {path}") from e
    except json.JSONDecodeError as e:
        raise ConfigError(f"JSON invalide dans la configuration : {path}") from e

# Mal : Except nu
def load_config(path: str) -> Config:
    try:
        with open(path) as f:
            return Config.from_json(f.read())
    except:
        return None  # Échec silencieux !

Chaînage d'exceptions

def process_data(data: str) -> Result:
    try:
        parsed = json.loads(data)
    except json.JSONDecodeError as e:
        # Chaîner les exceptions pour préserver la trace
        raise ValueError(f"Échec de l'analyse des données : {data}") from e

Hiérarchie d'exceptions personnalisées

class AppError(Exception):
    """Exception de base pour toutes les erreurs de l'application."""
    pass

class ValidationError(AppError):
    """Levée lorsque la validation d'entrée échoue."""
    pass

class NotFoundError(AppError):
    """Levée lorsqu'une ressource demandée est introuvable."""
    pass

# Utilisation
def get_user(user_id: str) -> User:
    user = db.find_user(user_id)
    if not user:
        raise NotFoundError(f"Utilisateur introuvable : {user_id}")
    return user

Gestionnaires de contexte

Gestion des ressources

# Bien : Utilisation des gestionnaires de contexte
def process_file(path: str) -> str:
    with open(path, 'r') as f:
        return f.read()

# Mal : Gestion manuelle des ressources
def process_file(path: str) -> str:
    f = open(path, 'r')
    try:
        return f.read()
    finally:
        f.close()

Gestionnaires de contexte personnalisés

from contextlib import contextmanager

@contextmanager
def timer(name: str):
    """Gestionnaire de contexte pour chronométrer un bloc de code."""
    start = time.perf_counter()
    yield
    elapsed = time.perf_counter() - start
    print(f"{name} a pris {elapsed:.4f} secondes")

# Utilisation
with timer("traitement des données"):
    process_large_dataset()

Classes de gestionnaires de contexte

class DatabaseTransaction:
    def __init__(self, connection):
        self.connection = connection

    def __enter__(self):
        self.connection.begin_transaction()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is None:
            self.connection.commit()
        else:
            self.connection.rollback()
        return False  # Ne pas supprimer les exceptions

# Utilisation
with DatabaseTransaction(conn):
    user = conn.create_user(user_data)
    conn.create_profile(user.id, profile_data)

Compréhensions et générateurs

Compréhensions de listes

# Bien : Compréhension de liste pour des transformations simples
names = [user.name for user in users if user.is_active]

# Mal : Boucle manuelle
names = []
for user in users:
    if user.is_active:
        names.append(user.name)

# Les compréhensions complexes doivent être développées
# Mal : Trop complexe
result = [x * 2 for x in items if x > 0 if x % 2 == 0]

# Bien : Utiliser une fonction génératrice
def filter_and_transform(items: Iterable[int]) -> list[int]:
    result = []
    for x in items:
        if x > 0 and x % 2 == 0:
            result.append(x * 2)
    return result

Expressions génératrices

# Bien : Générateur pour l'évaluation paresseuse
total = sum(x * x for x in range(1_000_000))

# Mal : Crée une grande liste intermédiaire
total = sum([x * x for x in range(1_000_000)])

Fonctions génératrices

def read_large_file(path: str) -> Iterator[str]:
    """Lit un fichier volumineux ligne par ligne."""
    with open(path) as f:
        for line in f:
            yield line.strip()

# Utilisation
for line in read_large_file("huge.txt"):
    process(line)

Classes de données et tuples nommés

Classes de données

from dataclasses import dataclass, field
from datetime import datetime

@dataclass
class User:
    """Entité utilisateur avec __init__, __repr__ et __eq__ automatiques."""
    id: str
    name: str
    email: str
    created_at: datetime = field(default_factory=datetime.now)
    is_active: bool = True

# Utilisation
user = User(
    id="123",
    name="Alice",
    email="[email protected]"
)

Classes de données avec validation

@dataclass
class User:
    email: str
    age: int

    def __post_init__(self):
        # Valider le format de l'email
        if "@" not in self.email:
            raise ValueError(f"Email invalide : {self.email}")
        # Valider la fourchette d'âge
        if self.age < 0 or self.age > 150:
            raise ValueError(f"Âge invalide : {self.age}")

Tuples nommés

from typing import NamedTuple

class Point(NamedTuple):
    """Point 2D immuable."""
    x: float
    y: float

    def distance(self, other: 'Point') -> float:
        return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5

# Utilisation
p1 = Point(0, 0)
p2 = Point(3, 4)
print(p1.distance(p2))  # 5.0

Décorateurs

Décorateurs de fonction

import functools
import time

def timer(func: Callable) -> Callable:
    """Décorateur pour chronométrer l'exécution d'une fonction."""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        elapsed = time.perf_counter() - start
        print(f"{func.__name__} a pris {elapsed:.4f}s")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(1)

# slow_function() affiche : slow_function a pris 1.0012s

Décorateurs paramétrés

def repeat(times: int):
    """Décorateur pour répéter une fonction plusieurs fois."""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            results = []
            for _ in range(times):
                results.append(func(*args, **kwargs))
            return results
        return wrapper
    return decorator

@repeat(times=3)
def greet(name: str) -> str:
    return f"Bonjour, {name}!"

# greet("Alice") retourne ["Bonjour, Alice!", "Bonjour, Alice!", "Bonjour, Alice!"]

Décorateurs basés sur des classes

class CountCalls:
    """Décorateur qui compte combien de fois une fonction est appelée."""
    def __init__(self, func: Callable):
        functools.update_wrapper(self, func)
        self.func = func
        self.count = 0

    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"{self.func.__name__} a été appelée {self.count} fois")
        return self.func(*args, **kwargs)

@CountCalls
def process():
    pass

# Chaque appel à process() affiche le nombre d'appels

Patrons de concurrence

Threading pour les tâches liées aux E/S

import concurrent.futures
import threading

def fetch_url(url: str) -> str:
    """Récupère une URL (opération liée aux E/S)."""
    import urllib.request
    with urllib.request.urlopen(url) as response:
        return response.read().decode()

def fetch_all_urls(urls: list[str]) -> dict[str, str]:
    """Récupère plusieurs URL en simultané avec des threads."""
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
        future_to_url = {executor.submit(fetch_url, url): url for url in urls}
        results = {}
        for future in concurrent.futures.as_completed(future_to_url):
            url = future_to_url[future]
            try:
                results[url] = future.result()
            except Exception as e:
                results[url] = f"Erreur : {e}"
    return results

Multiprocessing pour les tâches liées au CPU

def process_data(data: list[int]) -> int:
    """Calcul intensif en CPU."""
    return sum(x ** 2 for x in data)

def process_all(datasets: list[list[int]]) -> list[int]:
    """Traite plusieurs jeux de données avec plusieurs processus."""
    with concurrent.futures.ProcessPoolExecutor() as executor:
        results = list(executor.map(process_data, datasets))
    return results

Async/Await pour les E/S simultanées

import asyncio

async def fetch_async(url: str) -> str:
    """Récupère une URL de manière asynchrone."""
    import aiohttp
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def fetch_all(urls: list[str]) -> dict[str, str]:
    """Récupère plusieurs URL en simultané."""
    tasks = [fetch_async(url) for url in urls]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    return dict(zip(urls, results))

Organisation des paquets

Structure de projet standard

myproject/
├── src/
│   └── mypackage/
│       ├── __init__.py
│       ├── main.py
│       ├── api/
│       │   ├── __init__.py
│       │   └── routes.py
│       ├── models/
│       │   ├── __init__.py
│       │   └── user.py
│       └── utils/
│           ├── __init__.py
│           └── helpers.py
├── tests/
│   ├── __init__.py
│   ├── conftest.py
│   ├── test_api.py
│   └── test_models.py
├── pyproject.toml
├── README.md
└── .gitignore

Conventions d'importation

# Bien : Ordre des imports - bibliothèque standard, tiers, local
import os
import sys
from pathlib import Path

import requests
from fastapi import FastAPI

from mypackage.models import User
from mypackage.utils import format_name

# Bien : Utiliser isort pour le tri automatique des imports
# pip install isort

init.py pour les exportations de paquets

# mypackage/__init__.py
"""mypackage - Un exemple de paquet Python."""

__version__ = "1.0.0"

# Exporter les classes/fonctions principales au niveau du paquet
from mypackage.models import User, Post
from mypackage.utils import format_name

__all__ = ["User", "Post", "format_name"]

Mémoire et performances

Utiliser slots pour l'efficacité mémoire

# Mal : Classe normale utilisant __dict__ (plus de mémoire)
class Point:
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

# Bien : __slots__ réduit l'utilisation mémoire
class Point:
    __slots__ = ['x', 'y']

    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

Générateur pour les grandes données

# Mal : Retourne la liste complète en mémoire
def read_lines(path: str) -> list[str]:
    with open(path) as f:
        return [line.strip() for line in f]

# Bien : Génère les lignes une par une
def read_lines(path: str) -> Iterator[str]:
    with open(path) as f:
        for line in f:
            yield line.strip()

Éviter la concaténation de chaînes dans les boucles

# Mal : O(n²) à cause de l'immutabilité des chaînes
result = ""
for item in items:
    result += str(item)

# Bien : O(n) avec join
result = "".join(str(item) for item in items)

# Bien : Utiliser StringIO pour la construction
from io import StringIO

buffer = StringIO()
for item in items:
    buffer.write(str(item))
result = buffer.getvalue()

Intégration des outils Python

Commandes essentielles

# Formatage du code
black .
isort .

# Linting
ruff check .

# Vérification de type
mypy .

# Tests
pytest .

# Construction
python -m build

# Gestion des dépendances (nécessite pip install uv)
uv sync

Configuration de pyproject.toml

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "mypackage"
version = "1.0.0"
requires-python = ">=3.9"
dependencies = [
    "requests>=2.28",
]

[project.optional-dependencies]
dev = [
    "black",
    "isort",
    "ruff",
    "mypy",
    "pytest",
]

[tool.black]
line-length = 88

[tool.isort]
profile = "black"

[tool.ruff]
line-length = 88

[tool.mypy]
warn_unused_configs = true
warn_unused_ignores = true

Ressources

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Skills associés