Mis à jour le

🐍
Senior 25 questions • Python

Questions Python Senior

25 questions avancees pour les entretiens Python senior. Metaclasses, descripteurs, concurrence, optimisation et architecture.

1. Expliquez les décorateurs avances et les metaclasses en Python.

Les décorateurs sont des fonctions qui modifient le comportement d'autres fonctions ou classes. Un décorateur reçoit une fonction et retourne une nouvelle fonction (ou la même modifiée). Les décorateurs avec arguments nécessitent une triple imbrication : la factory retourne le décorateur qui retourne le wrapper. functools.wraps preserve les metadata de la fonction originale. Les décorateurs de classe modifient ou enrichissent des classes entières. Les metaclasses controlent la création des classes (la classe d'une classe). type est la metaclasse par défaut. Définir une metaclasse avec class Meta(type) et surcharger new ou init. Cas d'utilisation : validation de schéma, enregistrement automatique, API frameworks (Django models). ABCMeta pour les classes abstraites. En général, préférer les décorateurs aux metaclasses (plus simples).

2. Comment fonctionne le GIL et comment contourner ses limitations ?

Le GIL (Global Interpréter Lock) est un mutex dans CPython qui empêche l'exécution simultanee de bytecode Python par plusieurs threads. Conséquence : le multithreading Python ne parallelise pas les tâches CPU-bound. Le GIL est libère pendant les opérations I/O, ce qui rend le threading utile pour les tâches I/O-bound (requêtes HTTP, accès fichier). Solutions pour le CPU-bound : multiprocessing (processus séparés, chacun avec son propre GIL), concurrent.futures.ProcessPoolExecutor (API simplifiée), extensions C/Cython (liberent le GIL pendant le calcul), numpy/pandas (opérations vectorisees en C). Python 3.13+ introduit le mode free-threaded (sans GIL, optionnel). asyncio pour le I/O-bound concurrent dans un seul thread.

3. Expliquez les générateurs, les coroutines et async/await.

Les générateurs (yield) produisent des valeurs paresseusement. Ils implementent le protocole iterateur et conservent leur état entre les appels next(). Les generator expressions (x for x in range(n)) sont des générateurs inline. Les coroutines (async def) sont des fonctions qui peuvent être suspendues avec await. asyncio gere la boucle événementielle. await suspend la coroutine et rend le contrôle à la boucle qui peut exécuter d'autres coroutines. asyncio.gather() execute plusieurs coroutines en parallèle. Les async generators (async def avec yield) combinent les deux concepts. Les context managers asynchrones (async with) pour les ressources asynchrones. La différence clef : les générateurs sont pull-based (on demande la valeur), les coroutines sont push-based (elles attendent des événements).

4. Comment structurer un projet Python de manière professionnelle ?

Structure recommandee : src layout (src/monpackage/) pour éviter les imports accidentels depuis le répertoire racine. Fichiers essentiels : pyproject.toml (metadata, dépendances, configuration des outils), README.md, LICENSE. Gestion des dépendances : Poetry ou uv pour le lockfile reproductible. Tests : dossier tests/ avec pytest, conftest.py pour les fixtures partagees. Linting : ruff (remplace flake8 + isort + black, ultra rapide). Type checking : mypy ou pyright avec des annotations de type. Pre-commit hooks : ruff, mypy, tests rapides. CI/CD : GitHub Actions avec matrix testing (Python 3.10, 3.11, 3.12). Documentation : docstrings Google/NumPy style, Sphinx ou MkDocs pour la génération. Logging : module logging avec configuration structurée (pas de print).

5. Quels sont les patterns de concurrence en Python ?

Threading (concurrent.futures.ThreadPoolExecutor) : pour les tâches I/O-bound (appels API, lecture de fichiers). Partage de mémoire, mais limite par le GIL. Multiprocessing (ProcessPoolExecutor) : pour les tâches CPU-bound. Processus séparés, pas de GIL, mais coût de communication inter-processus (sérialisation). asyncio : pour le I/O-bound concurrent dans un seul thread, très performant pour les milliers de connexions simultanées (serveurs web, scrapers). Patterns : producer-consumer avec asyncio.Queue, fan-out/fan-in, semaphore pour limiter la concurrence. Trio : alternative a asyncio avec une conception plus sure (structured concurrency). Choix : asyncio pour les serveurs et le networking, threads pour le I/O simple, multiprocessing pour le calcul numérique.

6. Expliquez les descripteurs et le protocole de descripteur en Python.

Les descripteurs sont des objets qui définissent get, set, ou delete. Ils controlent l'accès aux attributs d'une classe. Les data descriptors (avec set ou delete) ont priorité sur le dict de l'instance. Les non-data descriptors (seulement get) ont une priorité plus basse. Les propriétés (@property) sont implementees comme des descripteurs. Les méthodes sont des non-data descriptors (self est lie via get). Les classmethod et staticmethod sont aussi des descriptors. Cas d'utilisation : validation d'attributs, lazy loading, logging d'accès, computed attributes, ORMs (champs de modèles Django/SQLAlchemy). Le protocole de descripteur est le mécanisme fondamental derrière de nombreuses fonctionnalités de Python : properties, methods, classmethod, staticmethod, slots.

7. Comment optimiser les performances en Python ?

Stratégies par ordre de priorité : 1) Algorithme : choisir la bonne structure de données (dict O(1) vs list O(n) pour les lookups). 2) Built-ins : utiliser les fonctions C natives (sum, min, max, sorted, collections.Counter). 3) Compréhensions : plus rapides que les boucles for equivalentes. 4) Profilage : cProfile pour le CPU, memory_profiler pour la mémoire, py-spy pour le profilage sans overhead. 5) Caching : functools.lru_cache ou functools.cache pour la memoization. 6) NumPy/Pandas : opérations vectorisees pour les données numériques. 7) Cython/Numba : compilation en C pour les boucles critiques. 8) PyPy : interpreteur JIT alternatif (acceleration 2-10x sans changer le code). Éviter les micro-optimisations avant de profiler.

8. Qu'est-ce que le typing avance en Python ?

Depuis Python 3.5+, le type hinting ajoute des annotations de type. Types avances : Union (int | str depuis 3.10), Optional (T | None), Literal (valeurs spécifiques), TypeVar (génériques), Protocol (structural typing, comme les interfaces sans héritage). Generic classes et fonctions avec TypeVar. TypedDict pour typer les dictionnaires avec des clés connues. ParamSpec et Concatenate pour typer les décorateurs preservant les signatures. dataclasses comme alternative typee aux NamedTuples. Overload pour les signatures multiples. Les outils mypy et pyright vérifient les types statiquement. Les types sont ignores au runtime (sauf si utilisees avec des outils comme pydantic ou beartype pour la validation runtime).

9. Expliquez les context managers et le protocole with en Python.

Les context managers gèrent les ressources avec le pattern acquire-use-release. Protocole : enter (acquisition, retourne la ressource) et exit (liberation, reçoit les infos d'exception). Le bloc with garantit que exit est appele même en cas d'exception. contextlib.contextmanager simplifie la création avec un générateur (yield entre le setup et le teardown). Cas d'utilisation : fichiers (open), connexions DB, locks (threading.Lock), transactions, modifications temporaires (chdir, env vars), mesure de temps, suppression d'exceptions (contextlib.suppress). contextlib.ExitStack gere dynamiquement un nombre variable de context managers. Les async context managers (async with) avec aenter/aexit pour les ressources asynchrones.

10. Comment gérer les tests avances en Python ?

pytest est le standard. Fixtures : fonctions qui fournissent des données ou des ressources aux tests. Scopes : function (défaut), class, module, session. Parametrize : exécuter un test avec plusieurs jeux de données. Mocking : unittest.mock.patch pour remplacer des dépendances (API, DB). monkeypatch (fixture pytest) pour modifier l'environnement. conftest.py : fixtures partagees entre les fichiers de test, auto-decouverts. Markers : @pytest.mark.slow pour categoriser les tests. Coverage : pytest-cov pour mesurer la couverture. Factories : factory_boy pour générer des objets de test. Property-based testing : Hypothesis genere automatiquement des cas de test. Intégration tests : testcontainers pour lancer des conteneurs Docker (DB, Redis) pendant les tests. Organisation : tests/unit/ et tests/intégration/ séparés.

Besoin d'aide pour préparer vos entretiens ?

Decrivez votre profil pour des conseils de preparation personnalises.

Recevoir des conseils

Questions fréquentes

Quel salaire attendre pour un senior Python en France ?
Un developpeur Python senior peut attendre entre 55 000 et 75 000 EUR brut annuel en province, et 65 000 a 90 000 EUR en Ile-de-France.
Quelles competences complementaires sont attendues ?
Architecture logicielle, Docker/Kubernetes, CI/CD, bases de donnees (SQL et NoSQL), et experience avec les frameworks (Django, FastAPI).

Pages liées

Chaque semaine, le meilleur de la tech française

Tendances, salaires, outils et opportunités — directement dans votre boîte mail.

Gratuit. Desabonnement en un clic. Pas de spam.