MFormations
Modern Python Engineering

Chapitre 18

Chapitre 18 : QCM — 100 Questions à Choix Multiples

> **Évaluez vos connaissances** à travers 100 QCM couvrant l'intégralité du programme Modern Python Engineering.

Chapitre 18 — 100 Questions à Choix Multiples

Version : 1.0.0
Durée estimée : 90 minutes
Barème : 1 point par question, pas de points négatifs


Module 1 : Syntaxe et fondamentaux (Q01–Q15)

Q01. Quelle est la sortie de print(type(1/2)) ?

  • A. <class 'int'>
  • B. <class 'float'>
  • C. <class 'double'>
  • D. <class 'number'>

Réponse : B — En Python 3, la division / retourne toujours un float.


Q02. Quelle est la différence entre is et == ?

  • A. is compare les valeurs, == compare les identités
  • B. is compare les identités, == compare les valeurs
  • C. Les deux sont identiques
  • D. is est déprécié depuis Python 3.12

Réponse : B — is vérifie l'identité mémoire (id()), == vérifie l'égalité via __eq__.


Q03. Quel est le résultat de 3 * 'abc' + 'def' ?

  • A. abcabcdef
  • B. abcabcabcdef
  • C. TypeError
  • D. abcabc def

Réponse : B — 3 * 'abc''abcabcabc', puis + 'def''abcabcabcdef'.


Q04. Quelle méthode de liste modifie la liste originale ?

  • A. sorted()
  • B. list.sort()
  • C. reversed()
  • D. list.copy()

Réponse : B — list.sort() trie la liste en place. sorted() retourne une nouvelle liste.


Q05. Quelle est la sortie de print(list(range(5, 1, -1))) ?

  • A. [5, 4, 3, 2]
  • B. [5, 4, 3, 2, 1]
  • C. [4, 3, 2]
  • D. [5, 4, 3]

Réponse : A — range(5, 1, -1) commence à 5, s'arrête avant 1, avec un pas de -1.


Q06. Quelle est la sortie de print(not True and False or True) ?

  • A. True
  • B. False
  • C. None
  • D. SyntaxError

Réponse : A — L'ordre est : not TrueFalse, False and FalseFalse, False or TrueTrue.


Q07. Que retourne any([[], [0], ['']]) ?

  • A. True
  • B. False
  • C. None
  • D. TypeError

Réponse : A — [] est falsy, [0] est truthy (liste non-vide), [''] est truthy.


Q08. Quel est le résultat de {x: x**2 for x in range(5) if x % 2 == 0} ?

  • A. {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
  • B. {0: 0, 2: 4, 4: 16}
  • C. {0: 0, 2: 4}
  • D. {1: 1, 3: 9}

Réponse : B — range(5) = 0, 1, 2, 3, 4. Filtre x % 2 == 0 = 0, 2, 4.


Q09. Que fait *args dans une signature de fonction ?

  • A. Déballe un dictionnaire
  • B. Capture les arguments positionnels supplémentaires dans un tuple
  • C. Capture les arguments nommés supplémentaires dans un dict
  • D. Déclare un argument optionnel

Réponse : B — *args capture les arguments positionnels supplémentaires. **kwargs capture les nommés.


Q10. Quelle est la sortie de print("{{}}".format("x")) ?

  • A. x
  • B. {}
  • C. {{}}
  • D. {x}

Réponse : B — Les doubles accolades {{}} s'échappent en accolades littérales.


Q11. Que retourne frozenset([1, 2, 2, 3]) ?

  • A. {1, 2, 3}
  • B. frozenset({1, 2, 3})
  • C. {1, 2, 2, 3}
  • D. [1, 2, 3]

Réponse : B — frozenset déduplique les éléments et retourne un set immuable.


Q12. Quel est le bon ordre de précédence des opérateurs (du plus fort au plus faible) ?

  • A. (), **, *, +, ==, not, and, or
  • B. (), **, *, +, ==, and, or, not
  • C. **, (), *, +, ==, not, or, and
  • D. (), **, ==, *, +, and, or, not

Réponse : A — Parenthèses > Exponentiation > Multiplication > Addition > Comparaison > not > and > or.


Q13. Quelle est la sortie de print(0.1 + 0.2 == 0.3) ?

  • A. True
  • B. False
  • C. TypeError
  • D. None

Réponse : B — Erreur de représentation flottante : 0.1 + 0.2 = 0.30000000000000004.


Q14. Que retourne bool([]) ?

  • A. True
  • B. False
  • C. None
  • D. TypeError

Réponse : B — Les séquences vides ([], {}, (), "", set()) sont falsy.


Q15. Quelle est la sortie de print(1 if False else 2 if False else 3) ?

  • A. 1
  • B. 2
  • C. 3
  • D. SyntaxError

Réponse : C — Expression ternaire droite-associative : 1 if False else (2 if False else 3).


Module 2 : Programmation orientée objet (Q16–Q25)

Q16. Que retourne isinstance(3.14, (int, float)) ?

  • A. True
  • B. False
  • C. TypeError
  • D. None

Réponse : A — 3.14 est instance de float, qui est dans le tuple.


Q17. Quelle méthode doit-on implémenter pour utiliser len() sur un objet ?

  • A. __length__
  • B. __len__
  • C. __size__
  • D. __bool__

Réponse : B — __len__ est appelée par la fonction native len().


Q18. Que permet le paramètre slots=True dans un @dataclass (Python 3.10+) ?

  • A. Déclarer des champs optionnels
  • B. Générer automatiquement __slots__ pour économiser la mémoire
  • C. Figer l'instance (empêcher les mutations)
  • D. Activer l'héritage multiple

Réponse : B — slots=True génère __slots__, réduisant la mémoire par instance.


Q19. Quelle est la différence entre @staticmethod et @classmethod ?

  • A. Aucune, ce sont des synonymes
  • B. @classmethod reçoit la classe comme premier argument, pas @staticmethod
  • C. @staticmethod peut modifier l'état de la classe
  • D. @classmethod ne peut être appelé que sur des instances

Réponse : B — @classmethod reçoit cls, @staticmethod ne reçoit rien d'implicite.


Q20. Que retourne type(type) ?

  • A. <class 'type'>
  • B. <class 'object'>
  • C. <class 'function'>
  • D. NoneType

Réponse : A — type est une métaclasse, sa métaclasse est elle-même.


Q21. Quel protocole permet d'utiliser async for sur un objet ?

  • A. __iter__ / __next__
  • B. __aiter__ / __anext__
  • C. __await__
  • D. __enter__ / __exit__

Réponse : B — Le protocole asynchrone d'itération utilise __aiter__ et __anext__.


Q22. Que fait l'héritage multiple si deux classes parentes définissent la même méthode ?

  • A. Python lève une exception
  • B. La première classe dans le MRO gagne
  • C. La dernière classe dans le MRO gagne
  • D. Les deux méthodes sont fusionnées

Réponse : B — Le MRO (Method Resolution Order) donne priorité à la première classe listée.


Q23. Quelle est la sortie de print(type(1).__mro__) ?

  • A. (<class 'int'>, <class 'object'>)
  • B. (<class 'object'>, <class 'int'>)
  • C. (<class 'int'>,)
  • D. (<class 'int'>, <class 'float'>, <class 'object'>)

Réponse : A — L'ordre de résolution des méthodes pour int est intobject.


Q24. Quelle fonction retourne toutes les méthodes d'un objet ?

  • A. vars()
  • B. dir()
  • C. help()
  • D. locals()

Réponse : B — dir() retourne la liste des attributs et méthodes d'un objet.


Q25. Quel décorateur transforme une méthode en propriété en lecture seule ?

  • A. @classmethod
  • B. @property
  • C. @staticmethod
  • D. @abstractmethod

Réponse : B — @property permet d'accéder à une méthode comme un attribut.


Module 3 : Typage statique (Q26–Q32)

Q26. Quel est le type de retour de def func(a: int) -> str: ... si la fonction retourne None ?

  • A. mypy lève une erreur
  • B. Python lève une erreur à l'exécution
  • C. Aucune erreur, mais mypy signale une incohérence
  • D. Le type hint est ignoré

Réponse : C — mypy détecte l'incohérence entre l'annotation et le retour effectif.


Q27. Que signifie list[int] comme annotation ?

  • A. Une liste qui ne contient que des entiers
  • B. Un dictionnaire listant des entiers
  • C. Une liste d'entiers (information pour l'analyse statique)
  • D. Une liste avec un index entier

Réponse : C — list[int] est un générique annotant le type des éléments pour l'analyse statique.


Q28. Quel module contient Protocol pour le duck typing statique ?

  • A. abc
  • B. typing
  • C. collections.abc
  • D. dataclasses

Réponse : B — typing.Protocol (PEP 544) définit des protocoles pour le duck typing statique.


Q29. Que fait TypeVar('T', bound=float) ?

  • A. Définit T comme égal à float
  • B. Définit T avec float comme borne supérieure
  • C. Définit T comme une sous-classe de float
  • D. Définit T comme une liste de float

Réponse : B — bound=float signifie T peut être float ou n'importe quel sous-type.


Q30. Quel type utiliser pour une fonction qui peut retourner soit str, soit None ?

  • A. str | None
  • B. Optional[str]
  • C. Les deux A et B sont valides
  • D. Union[str, None]

Réponse : C — Les deux syntaxes sont équivalentes. str | None (PEP 604) est recommandée.


Q31. Que signifie Final dans from typing import Final ?

  • A. La variable ne peut pas être réaffectée
  • B. La variable est privée
  • C. La variable est globale
  • D. La variable est évaluée paresseusement

Réponse : A — Final indique qu'une variable ne doit pas être réaffectée (vérifié par mypy).


Q32. Quelle annotation utiliser pour une fonction qui ne retourne jamais (boucle infinie, levée d'exception) ?

  • A. -> None
  • B. -> Never
  • C. -> NoReturn
  • D. -> Void

Réponse : B ou C — Never (PEP 484) et NoReturn sont tous deux valides, Never est recommandé.


Module 4 : Programmation asynchrone (Q33–Q42)

Q33. Quelle fonction exécute une coroutine et retourne son résultat ?

  • A. async.run()
  • B. await
  • C. asyncio.run()
  • D. coroutine.send()

Réponse : C — asyncio.run() est le point d'entrée standard pour exécuter une coroutine.


Q34. Que se passe-t-il si une exception non gérée survient dans une tâche asyncio ?

  • A. La tâche est silencieusement ignorée
  • B. L'exception est levée quand on await la tâche
  • C. Le programme crashe immédiatement
  • D. L'exception est loggée automatiquement

Réponse : B — Si la tâche est awaitée, l'exception est propagée. Sinon, elle est stockée dans la tâche.


Q35. Que fait asyncio.gather() si l'une des coroutines lève une exception ?

  • A. Toutes les coroutines sont annulées immédiatement
  • B. L'exception est levée quand on attend le résultat, les autres continuent
  • C. Les coroutines continuent, l'exception est ignorée
  • D. gather retourne None pour la coroutine en erreur

Réponse : B — Avec return_exceptions=False (défaut), l'exception est levée immédiatement et les autres tâches continuent.


Q36. Quelle est la différence entre asyncio.create_task() et asyncio.ensure_future() ?

  • A. Aucune
  • B. create_task() est plus haut niveau et préféré
  • C. ensure_future() lance la coroutine immédiatement
  • D. create_task() est synchrone

Réponse : B — create_task() est l'API moderne recommandée. ensure_future() accepte aussi des futures.


Q37. Que retourne une fonction définie avec async def quand elle est appelée ?

  • A. Une coroutine
  • B. Un Future
  • C. Une Task
  • D. Le résultat directement

Réponse : A — async def retourne un objet coroutine, pas le résultat.


Q38. Quel context manager asynchrone est utilisé pour créer un groupe de tâches ?

  • A. asyncio.TaskGroup()
  • B. asyncio.gather()
  • C. asyncio.wait()
  • D. asyncio.create_task()

Réponse : A — asyncio.TaskGroup() (Python 3.11+) est un context manager pour gérer des tâches.


Q39. Que fait asyncio.timeout(5) ?

  • A. Limite le temps d'exécution d'un bloc à 5 secondes
  • B. Met en pause l'exécution pendant 5 secondes
  • C. Définit un délai avant l'exécution
  • D. Mesure le temps d'exécution

Réponse : A — asyncio.timeout() (Python 3.12+) lève TimeoutError si le dépasse.


Q40. Quelle est la sortie probable de ce code ?

async def main():
    async with asyncio.TaskGroup() as tg:
        tg.create_task(asyncio.sleep(1))
    print("Done")
  • A. Done est imprimé après 1 seconde
  • B. Done est imprimé immédiatement
  • C. Erreur : les tâches ne sont pas awaitées
  • D. Le programme ne termine jamais

Réponse : A — TaskGroup attend que toutes les tâches se terminent avant de sortir du context manager.


Q41. Quel module permet d'écrire du code asynchrone compatible avec asyncio et trio ?

  • A. asyncio
  • B. anyio
  • C. trio
  • D. curio

Réponse : B — anyio fournit une abstraction indépendante de la bibliothèque asynchrone.


Q42. Quel est le problème avec ce code ?

async def fetch_all(urls):
    for url in urls:
        await fetch(url)
  • A. Syntax error
  • B. Les appels sont séquentiels, pas concurrents
  • C. fetch doit être une coroutine
  • D. Aucun problème

Réponse : B — Les appels sont awaités un par un. Il faut utiliser asyncio.gather() ou TaskGroup.


Module 5 : Web / FastAPI (Q43–Q52)

Q43. Quel décorateur crée une route GET dans FastAPI ?

  • A. @app.get()
  • B. @app.route('/path', methods=['GET'])
  • C. @app.get('/path')
  • D. @api.get('/path')

Réponse : C — @app.get('/path') est la syntaxe FastAPI pour une route GET.


Q44. Quel module FastAPI utilise pour la validation des données ?

  • A. json
  • B. pydantic
  • C. marshmallow
  • D. attrs

Réponse : B — FastAPI s'appuie sur Pydantic pour la validation des modèles de données.


Q45. Que retourne Query(ge=1, le=100) dans un paramètre de fonction ?

  • A. Un paramètre de requête optionnel
  • B. Un paramètre de requête avec validation (≥1 et ≤100)
  • C. Une query SQL
  • D. Un paramètre de chemin

Réponse : B — Query(ge=1, le=100) valide que le paramètre est entre 1 et 100.


Q46. Que fait Depends() dans FastAPI ?

  • A. Déclare une dépendance obligatoire
  • B. Injecte le résultat d'une fonction comme paramètre
  • C. Déclare un middleware
  • D. Ajoute une route dépendante

Réponse : B — Depends() est le mécanisme d'injection de dépendances de FastAPI.


Q47. Quel est le bon code de statut HTTP pour une création réussie ?

  • A. 200
  • B. 201
  • C. 202
  • D. 204

Réponse : B — 201 Created est le code standard pour une création réussie.


Q48. Quel schéma OAuth2 FastAPI utilise-t-il pour protéger les routes ?

  • A. OAuth2PasswordBearer
  • B. OAuth2AuthorizationCode
  • C. OAuth2ClientCredentials
  • D. OAuth2Implicit

Réponse : A — OAuth2PasswordBearer est le schéma intégré pour le flow password.


Q49. Comment FastAPI génère-t-il automatiquement la documentation ?

  • A. Javadoc
  • B. Sphinx
  • C. Swagger UI (OpenAPI) et ReDoc
  • D. MkDocs

Réponse : C — FastAPI expose automatiquement Swagger UI sur /docs et ReDoc sur /redoc.


Q50. Que permet responses_model dans un décorateur de route ?

  • A. Définir le modèle de réponse pour la validation
  • B. Définir le modèle de requête
  • C. Définir le modèle de base de données
  • D. Définir le modèle de template

Réponse : A — response_model valide et filtre la réponse selon le modèle Pydantic.


Q51. Quel décorateur WebSocket FastAPI doit-on utiliser ?

  • A. @app.websocket('/ws')
  • B. @app.ws('/ws')
  • C. @app.socket('/ws')
  • D. @app.ws_route('/ws')

Réponse : A — @app.websocket('/ws') définit une route WebSocket.


Q52. Que retourne HTTPException(status_code=404) dans FastAPI ?

  • A. Une réponse JSON avec une erreur
  • B. Une page HTML 404
  • C. Une redirection
  • D. Une exception Python standard

Réponse : A — FastAPI convertit automatiquement HTTPException en réponse JSON.


Module 6 : Data (pandas, numpy) (Q53–Q62)

Q53. Que retourne df.head() sur un DataFrame pandas ?

  • A. Les 5 premières lignes
  • B. Les 5 dernières lignes
  • C. Les statistiques descriptives
  • D. Le nom des colonnes

Réponse : A — Par défaut, head() retourne les 5 premières lignes.


Q54. Quelle méthode pandas supprime les lignes avec des valeurs manquantes ?

  • A. df.fillna()
  • B. df.dropna()
  • C. df.drop()
  • D. df.remove_na()

Réponse : B — dropna() supprime les lignes contenant des NaN.


Q55. Quelle est la sortie de pd.Series([1, 2, 3]).mean() ?

  • A. 1.0
  • B. 2.0
  • C. 3.0
  • D. 6.0

Réponse : B — La moyenne de 1, 2, 3 est 2.0.


Q56. Comment regrouper par une colonne et calculer la moyenne ?

  • A. df.groupby('col').mean()
  • B. df.group('col').avg()
  • C. df.aggregate('col', 'mean')
  • D. df.pivot('col').mean()

Réponse : A — groupby('col').mean() est la syntaxe pandas standard.


Q57. Que fait pd.merge(df1, df2, on='id', how='left') ?

  • A. Concatène df1 et df2 verticalement
  • B. Joint df1 et df2 sur la colonne id, gardant toutes les lignes de df1
  • C. Joint df1 et df2 sur la colonne id, gardant seulement les intersections
  • D. Fusionne les colonnes de df1 et df2

Réponse : B — how='left' garde toutes les lignes de la table de gauche (df1).


Q58. Quel est l'avantage de numpy par rapport aux listes Python ?

  • A. Vérification de type à la compilation
  • B. Opérations vectorisées plus rapides
  • C. Gestion automatique de la mémoire
  • D. Support natif du multithreading

Réponse : B — numpy utilise des opérations vectorisées en C, bien plus rapides que les boucles Python.


Q59. Que retourne df['col'].value_counts() ?

  • A. Le nombre de valeurs uniques
  • B. Le comptage de chaque valeur distincte
  • C. Les valeurs triées
  • D. Les statistiques descriptives

Réponse : B — value_counts() compte les occurrences de chaque valeur distincte.


Q60. Comment appliquer une fonction à chaque élément d'une colonne pandas ?

  • A. df['col'].apply(func)
  • B. df['col'].map(func)
  • C. df['col'].transform(func)
  • D. Les deux A et B fonctionnent

Réponse : D — apply() et map() peuvent toutes deux appliquer une fonction élément par élément.


Q61. Que retourne pd.to_datetime('2024-01-15') ?

  • A. Timestamp('2024-01-15')
  • B. '2024-01-15'
  • C. datetime(2024, 1, 15)
  • D. date(2024, 1, 15)

Réponse : A — pd.to_datetime() retourne un objet Timestamp pandas.


Q62. Quelle méthode calcule la matrice de corrélation d'un DataFrame ?

  • A. df.cov()
  • B. df.corr()
  • C. df.correlate()
  • D. df.correlation()

Réponse : B — df.corr() calcule la matrice de corrélation de Pearson.


Module 7 : Machine Learning (Q63–Q70)

Q63. Que fait train_test_split() de scikit-learn ?

  • A. Divise les données en features et target
  • B. Divise les données en ensembles d'entraînement et de test
  • C. Normalise les données
  • D. Standardise les données

Réponse : B — train_test_split() partitionne aléatoirement en training et test sets.


Q64. Quel métrique est appropriée pour un problème de classification binaire déséquilibré ?

  • A. Accuracy
  • B. F1-score
  • C. Mean Absolute Error
  • D. R²

Réponse : B — Le F1-score est préféré pour les datasets déséquilibrés car il combine précision et rappel.


Q65. Que fait StandardScaler dans un pipeline ?

  • A. Supprime les valeurs aberrantes
  • B. Centre et réduit les features (moyenne=0, variance=1)
  • C. Normalise entre 0 et 1
  • D. Convertit les catégories en nombres

Réponse : B — StandardScaler standardise les features : (x - μ) / σ.


Q66. Quel est le risque principal du Grid Search avec trop de paramètres ?

  • A. Underfitting
  • B. Overfitting (data leakage)
  • C. Temps d'exécution exponentiel
  • D. Instabilité numérique

Réponse : C — Le nombre de combinaisons croît exponentiellement avec le nombre de paramètres.


Q67. Que fait cross_val_score() ?

  • A. Évalue un modèle avec validation croisée
  • B. Calcule les scores de corrélation croisée
  • C. Valide les features sélectionnées
  • D. Croise les résultats de plusieurs modèles

Réponse : A — cross_val_score() applique la validation croisée et retourne les scores.


Q68. Quel est l'avantage de RandomForestClassifier sur un arbre de décision simple ?

  • A. Plus rapide à l'entraînement
  • B. Moins de variance, meilleure généralisation
  • C. Plus simple à interpréter
  • D. Nécessite moins de données

Réponse : B — Random Forest réduit la variance en moyennant plusieurs arbres.


Q69. Que signifie "overfitting" ?

  • A. Le modèle est trop simple
  • B. Le modèle apprend trop bien les données d'entraînement mais généralise mal
  • C. Le modèle est trop lent
  • D. Le modèle nécessite plus de features

Réponse : B — L'overfitting est un apprentissage excessif du bruit des données d'entraînement.


Q70. Quelle classe de scikit-learn permet de créer des pipelines de transformations et d'estimateurs ?

  • A. Pipeline
  • B. Chain
  • C. Flow
  • D. Sequential

Réponse : A — sklearn.pipeline.Pipeline enchaîne transformations et modèle final.


Module 8 : Architecture logicielle (Q71–Q78)

Q71. Quel principe SOLID stipule qu'une classe ne doit avoir qu'une seule raison de changer ?

  • A. Open/Closed Principle
  • B. Single Responsibility Principle
  • C. Liskov Substitution Principle
  • D. Dependency Inversion Principle

Réponse : B — SRP : chaque classe doit avoir une seule responsabilité.


Q72. Que signifie "injection de dépendances" ?

  • A. Créer des dépendances à l'intérieur d'une classe
  • B. Fournir les dépendances d'une classe de l'extérieur
  • C. Supprimer les dépendances d'une classe
  • D. Tester les dépendances d'une classe

Réponse : B — La DI consiste à passer les dépendances via le constructeur ou les paramètres.


Q73. Quel pattern permet de séparer la logique métier de la persistance ?

  • A. Singleton
  • B. Repository
  • C. Factory
  • D. Observer

Réponse : B — Le Repository pattern abstrait la couche de persistance.


Q74. Que représente une "Entity" dans la Clean Architecture ?

  • A. Un objet métier avec une identité unique
  • B. Une table de base de données
  • C. Une classe utilitaire
  • D. Un DTO

Réponse : A — Une Entity est un objet métier avec une identité (id) et une continuité.


Q75. Quel est le rôle d'un "Use Case" dans la Clean Architecture ?

  • A. Gérer la persistance
  • B. Orchestrer les opérations métier
  • C. Gérer les requêtes HTTP
  • D. Configurer l'application

Réponse : B — Un Use Case coordonne les entités pour réaliser une opération métier.


Q76. Que permet CQRS (Command Query Responsibility Segregation) ?

  • A. Séparer les lectures et écritures
  • B. Séparer le frontend et backend
  • C. Séparer la base de données de l'application
  • D. Séparer les tests unitaires et d'intégration

Réponse : A — CQRS utilise des modèles différents pour les commandes (écritures) et les queries (lectures).


Q77. Quel est l'avantage de l'architecture microservices ?

  • A. Simplicité du déploiement
  • B. Scalabilité indépendante des services
  • C. Base de données unique
  • D. Communication synchrone

Réponse : B — Les microservices peuvent être scalés indépendamment selon la charge.


Q78. Quel outil est utilisé pour gérer les migrations de base de données en Python ?

  • A. Git
  • B. Alembic
  • C. Docker
  • D. pip

Réponse : B — Alembic (par SQLAlchemy) gère les migrations de schéma de base de données.


Module 9 : Sécurité (Q79–Q86)

Q79. Quelle attaque consiste à injecter du code SQL via des entrées utilisateur ?

  • A. XSS
  • B. SQL Injection
  • C. CSRF
  • D. SSRF

Réponse : B — L'injection SQL exploite des entrées non sanitizées dans les requêtes SQL.


Q80. Comment prévenir l'injection SQL avec SQLAlchemy ?

  • A. Utiliser des chaînes formatées
  • B. Utiliser des requêtes paramétrées (texte avec bind params)
  • C. Échapper les guillemets manuellement
  • D. Utiliser eval()

Réponse : B — Les requêtes paramétrées avec bindparam() empêchent l'injection SQL.


Q81. Que signifie JWT ?

  • A. JavaScript Web Token
  • B. JSON Web Token
  • C. Java Web Token
  • D. JSON With Token

Réponse : B — JWT est un standard ouvert (RFC 7519) pour les tokens d'authentification.


Q82. Où stocker un secret d'application (clé API, mot de passe) ?

  • A. Dans le code source
  • B. Dans les variables d'environnement ou un gestionnaire de secrets
  • C. Dans la base de données
  • D. Dans les logs

Réponse : B — Les secrets doivent être stockés dans des variables d'environnement ou un vault.


Q83. Quelle attaque CSRF exploite-t-elle ?

  • A. La confiance qu'un site a dans le navigateur de l'utilisateur
  • B. La confiance qu'un site a dans l'utilisateur
  • C. La confiance qu'un utilisateur a dans un site
  • D. Les failles XSS

Réponse : A — CSRF force l'utilisateur à exécuter des actions non désirées sur un site où il est authentifié.


Q84. Comment FastAPI protège-t-il contre les attaques par déni de service ?

  • A. Rate limiting intégré
  • B. Limitation de taille de requête via max_size
  • C. Aucune protection intégrée, nécessite un middleware
  • D. Validation des types

Réponse : C — FastAPI n'a pas de rate limiting intégré. Il faut utiliser un middleware ou un reverse proxy.


Q85. Quelle bibliothèque Python est utilisée pour scanner les vulnérabilités de sécurité ?

  • A. pytest
  • B. bandit
  • C. black
  • D. isort

Réponse : B — Bandit est un analyseur de sécurité statique pour Python.


Q86. Quel est le principe de "défense en profondeur" ?

  • A. Utiliser un seul mécanisme de sécurité très fort
  • B. Superposer plusieurs couches de sécurité
  • C. Sécuriser uniquement le périmètre réseau
  • D. Faire confiance aux systèmes internes

Réponse : B — La défense en profondeur multiplie les barrières de sécurité.


Module 10 : DevOps & Docker (Q87–Q94)

Q87. Quel est l'avantage d'un Dockerfile multi-stage ?

  • A. Réduire la taille de l'image finale
  • B. Augmenter la vitesse de build
  • C. Permettre le déploiement sur plusieurs OS
  • D. Faciliter le debugging

Réponse : A — Multi-stage sépare l'environnement de build (volumineux) de l'image runtime (minimale).


Q88. Que fait l'instruction HEALTHCHECK dans un Dockerfile ?

  • A. Vérifie la santé du processus hôte
  • B. Définit une commande pour tester que le conteneur fonctionne
  • C. Installe des outils de santé
  • D. Vérifie les mises à jour de sécurité

Réponse : B — HEALTHCHECK permet à Docker de surveiller l'état du conteneur.


Q89. Quel est le but d'un CI/CD pipeline ?

  • A. Déployer manuellement les applications
  • B. Automatiser les tests et le déploiement
  • C. Écrire le code à la place du développeur
  • D. Gérer les bases de données

Réponse : B — CI/CD automatise l'intégration, les tests et le déploiement du code.


Q90. Que fait pytest --cov=src ?

  • A. Exécute les tests en parallèle
  • B. Mesure la couverture de code du dossier src
  • C. Ignore les tests échoués
  • D. Génère un rapport HTML

Réponse : B — --cov=src active la mesure de couverture pour le module src.


Q91. Quel outil est utilisé pour le linting Python dans ce projet ?

  • A. flake8
  • B. pylint
  • C. ruff
  • D. black

Réponse : C — Ce projet utilise ruff pour le linting et le formatting.


Q92. Que fait docker-compose up -d ?

  • A. Construit et démarre les services en arrière-plan
  • B. Démarre les services au premier plan
  • C. Arrête les services
  • D. Supprime les conteneurs

Réponse : A — -d (detach) démarre les conteneurs en arrière-plan.


Q93. Quel fichier configure les hooks de pre-commit ?

  • A. pyproject.toml
  • B. .pre-commit-config.yaml
  • C. .github/workflows/ci.yml
  • D. setup.cfg

Réponse : B — .pre-commit-config.yaml configure les hooks pre-commit.


Q94. Quelle commande Makefile exécute la suite complète de vérification (lint + test + security) ?

  • A. make lint
  • B. make all
  • C. make test
  • D. make verify

Réponse : B — make all exécute lint, test et security en séquence.


Module 11 : Python avancé (Q95–Q100)

Q95. Que permet une métaclasse ?

  • A. Créer des classes de manière dynamique
  • B. Modifier le comportement des instances
  • C. Personnaliser la création des classes
  • D. Ajouter des attributs aux instances

Réponse : C — Une métaclasse est une classe de classe qui personnalise la création des classes.


Q96. Quelle méthode est appelée par obj.attr = value ?

  • A. __getattr__
  • B. __setattr__
  • C. __delattr__
  • D. __getattribute__

Réponse : B — __setattr__(self, name, value) est appelée lors de l'affectation d'un attribut.


Q97. Que retourne eval("2 + 3 * 4") ?

  • A. 20
  • B. 14
  • C. 24
  • D. 9

Réponse : B — eval() exécute l'expression Python. Priorité des opérateurs : 3 * 4 = 12, 2 + 12 = 14.


Q98. Que fait un "descriptor" en Python ?

  • A. Décrit une classe avec des métadonnées
  • B. Définit __get__, __set__, __delete__ pour contrôler l'accès aux attributs
  • C. Sérialise une classe en JSON
  • D. Décore une fonction avec des informations de typage

Réponse : B — Un descriptor implémente le protocole des descripteurs (__get__/__set__/__delete__).


Q99. Que permet le module ast en Python ?

  • A. Analyser et manipuler l'arbre syntaxique abstrait du code Python
  • B. Générer des nombres aléatoires
  • C. Effectuer des calculs statistiques
  • D. Gérer les expressions asynchrones

Réponse : A — ast permet de parser, analyser et transformer le code Python.


Q100. Quelle est la sortie de ce code ?

class Meta(type):
    def __new__(mcs, name, bases, namespace):
        namespace['added'] = True
        return super().__new__(mcs, name, bases, namespace)

class A(metaclass=Meta):
    pass

print(A.added)
  • A. True
  • B. False
  • C. AttributeError
  • D. None

Réponse : A — La métaclasse Meta ajoute added = True au namespace de la classe lors de sa création.


Grille de correction

Utilisez la grille ci-dessous pour compter vos points :

QuestionsRéponses exactesScore
Q01-Q15.../15
Q16-Q25.../10
Q26-Q32.../7
Q33-Q42.../10
Q43-Q52.../10
Q53-Q62.../10
Q63-Q70.../8
Q71-Q78.../8
Q79-Q86.../8
Q87-Q94.../8
Q95-Q100.../6
Total.../100

Rendez-vous au chapitre 19 pour les corrigés détaillés de chaque question.