{
  "chapter": {
    "id": "modules",
    "level": "premiere",
    "theme": "Programmation",
    "title": "Modules Python",
    "description": "Notion de module, importation (`import`,\n`from ... import`), modules standards (`math`,\n`random`, `os`, `csv`...), création de ses propres\nmodules, espaces de noms, alias.",
    "prerequisites": [],
    "references": []
  },
  "questions": [
    {
      "id": "q01",
      "difficulty": 1,
      "skills": [
        "definition"
      ],
      "title": "Qu'est-ce qu'un module ?",
      "statement": "En Python, qu'est-ce qu'un **module** ?",
      "options": [
        {
          "text": "Un type de données",
          "correct": false,
          "feedback": "Erreur : un module est un fichier, pas un\ntype.\n"
        },
        {
          "text": "Un fichier `.py` contenant des fonctions, des classes ou des constantes réutilisables",
          "correct": true,
          "feedback": "Bonne réponse : un module regroupe du code\nréutilisable. On peut importer un module\ndans un autre programme pour utiliser ses\nfonctions sans les recoder.\n"
        },
        {
          "text": "Une boucle imbriquée",
          "correct": false,
          "feedback": "Une boucle imbriquée est\nune construction de\ncontrôle interne à une\nfonction. Un module est\nau contraire une unité\nd'organisation du code,\nstockée dans un fichier.\n"
        },
        {
          "text": "Une variable globale",
          "correct": false,
          "feedback": "Une variable globale est\nune variable accessible\ndans tout un programme.\nUn module, lui, est une\nunité d'organisation du\ncode, contenue dans un\nfichier source distinct.\n"
        }
      ],
      "explanation": "La modularité est un principe central en génie\nlogiciel : organiser le code en unités\ncohérentes et réutilisables, plutôt qu'un seul\ngros fichier."
    },
    {
      "id": "q02",
      "difficulty": 1,
      "skills": [
        "import"
      ],
      "title": "Import",
      "statement": "Comment **importer** le module `math` en Python ?",
      "options": [
        {
          "text": "`require math`",
          "correct": false,
          "feedback": "Erreur : c'est la syntaxe JavaScript / Ruby.\n"
        },
        {
          "text": "`use math`",
          "correct": false,
          "feedback": "Erreur : c'est la syntaxe Perl.\n"
        },
        {
          "text": "`include math`",
          "correct": false,
          "feedback": "Erreur : c'est la syntaxe C/C++.\n"
        },
        {
          "text": "`import math`",
          "correct": true,
          "feedback": "Bonne réponse : l'instruction `import` rend\naccessible le contenu du module via le\npréfixe `math.` (ex. `math.sqrt(2)`).\n"
        }
      ],
      "explanation": "`import math` charge le module et le rend\naccessible sous le nom `math`. Pour des\nfonctions précises sans préfixe :\n`from math import sqrt`."
    },
    {
      "id": "q03",
      "difficulty": 1,
      "skills": [
        "usage"
      ],
      "title": "Utilisation après import",
      "statement": "Après `import math`, comment appelle-t-on la\nfonction `sqrt` (racine carrée) ?",
      "options": [
        {
          "text": "`math->sqrt(2)`",
          "correct": false,
          "feedback": "Erreur : `->` est la syntaxe Perl/PHP.\n"
        },
        {
          "text": "`math.sqrt(2)`",
          "correct": true,
          "feedback": "Bonne réponse : on utilise le préfixe\n`module.fonction`.\n"
        },
        {
          "text": "`sqrt(2)`",
          "correct": false,
          "feedback": "Erreur : sans préfixe `math.`, Python ne\nconnaît pas `sqrt`.\n"
        },
        {
          "text": "`math::sqrt(2)`",
          "correct": false,
          "feedback": "Erreur : `::` est la syntaxe C++ ou Ruby.\n"
        }
      ],
      "explanation": "Préfixe = **espace de noms**. Évite les\nconflits si plusieurs modules ont des\nfonctions de même nom."
    },
    {
      "id": "q04",
      "difficulty": 1,
      "skills": [
        "from-import"
      ],
      "title": "from import",
      "statement": "Que fait `from math import sqrt` ?",
      "options": [
        {
          "text": "Importe tout le module `math`",
          "correct": false,
          "feedback": "Erreur : on importe seulement `sqrt`.\n"
        },
        {
          "text": "Importe seulement la fonction `sqrt`, qui devient appelable directement comme `sqrt(2)`",
          "correct": true,
          "feedback": "Bonne réponse : utile quand on n'a besoin\nque de quelques fonctions et qu'on veut\néviter le préfixe.\n"
        },
        {
          "text": "Cela ne fonctionne pas",
          "correct": false,
          "feedback": "Erreur : syntaxe valide.\n"
        },
        {
          "text": "Renomme `math` en `sqrt`",
          "correct": false,
          "feedback": "Le renommage à\nl'importation utilise\nle mot-clé `as`, par\nexemple `import math as\nm`. La syntaxe `from ...\nimport` ne renomme rien,\nelle expose un symbole\nprécis.\n"
        }
      ],
      "explanation": "Variantes : `from math import sqrt, pi` (deux\nnoms) ou `from math import *` (tout, mais à\néviter, pollue l'espace de noms)."
    },
    {
      "id": "q05",
      "difficulty": 1,
      "skills": [
        "math-pi"
      ],
      "title": "Constante pi",
      "statement": "Comment obtenir la valeur de π en Python ?",
      "options": [
        {
          "text": "`PI`",
          "correct": false,
          "feedback": "Erreur : pas de constante `PI` en majuscules.\n"
        },
        {
          "text": "`math.pi` (après `import math`)",
          "correct": true,
          "feedback": "Bonne réponse : `math.pi` ≈\n3.141592653589793. Pour la précision\nmaximale flottante.\n"
        },
        {
          "text": "`3.14`",
          "correct": false,
          "feedback": "C'est une approximation, mais le module\n`math` offre une valeur plus précise.\n"
        },
        {
          "text": "`pi`",
          "correct": false,
          "feedback": "Erreur : `pi` n'est pas une variable\nglobale par défaut. Il faut l'importer.\n"
        }
      ],
      "explanation": "Constantes utiles dans `math` : `math.pi`,\n`math.e`, `math.inf`, `math.nan`."
    },
    {
      "id": "q06",
      "difficulty": 1,
      "skills": [
        "random"
      ],
      "title": "Module random",
      "statement": "Quel module de la bibliothèque standard permet\nde générer des nombres aléatoires ?",
      "options": [
        {
          "text": "`numpy`",
          "correct": false,
          "feedback": "Existe et a un sous-module `random`, mais\nce n'est pas la bibliothèque **standard**\n(à installer séparément).\n"
        },
        {
          "text": "`math`",
          "correct": false,
          "feedback": "Erreur : `math` est pour les fonctions\nmathématiques classiques.\n"
        },
        {
          "text": "`random`",
          "correct": true,
          "feedback": "Bonne réponse : `random.randint(a, b)`,\n`random.choice(liste)`, `random.shuffle(...)`,\netc.\n"
        },
        {
          "text": "`stochastic`",
          "correct": false,
          "feedback": "Erreur : pas de module standard de ce nom.\n"
        }
      ],
      "explanation": "`random` est très utilisé en NSI Première\npour les jeux, les simulations, le tirage\naléatoire. Pour des usages cryptographiques,\npréférer `secrets` (plus sûr)."
    },
    {
      "id": "q07",
      "difficulty": 1,
      "skills": [
        "usage-randint"
      ],
      "title": "Tirage aléatoire",
      "statement": "Que fait `random.randint(1, 6)` ?",
      "options": [
        {
          "text": "Renvoie 6 (le maximum)",
          "correct": false,
          "feedback": "Erreur : c'est aléatoire, pas\nsystématiquement le max.\n"
        },
        {
          "text": "Renvoie une liste de 6 éléments",
          "correct": false,
          "feedback": "Erreur : un seul entier.\n"
        },
        {
          "text": "Renvoie un nombre flottant entre 1 et 6",
          "correct": false,
          "feedback": "Erreur : `randint` renvoie un **entier**.\n"
        },
        {
          "text": "Renvoie un entier aléatoire entre 1 et 6, inclus",
          "correct": true,
          "feedback": "Bonne réponse : simule un dé à 6 faces.\nAttention : contrairement à `range`, les\ndeux bornes sont **incluses**.\n"
        }
      ],
      "explanation": "Distinction subtile : `random.randint(a, b)`\n→ bornes **incluses** ; `random.randrange(a,\nb)` → b **exclue** (comme `range`)."
    },
    {
      "id": "q08",
      "difficulty": 1,
      "skills": [
        "import-as"
      ],
      "title": "Alias avec as",
      "statement": "Que fait `import numpy as np` ?",
      "options": [
        {
          "text": "Importe deux modules `numpy` et `np`",
          "correct": false,
          "feedback": "Erreur : un seul module avec deux noms.\n"
        },
        {
          "text": "Importe `numpy` mais le renomme en `np`",
          "correct": true,
          "feedback": "Bonne réponse : `as np` crée un **alias**.\nPratique pour les modules à nom long.\nConvention : `numpy as np`,\n`pandas as pd`, `matplotlib.pyplot as plt`.\n"
        },
        {
          "text": "Erreur de syntaxe",
          "correct": false,
          "feedback": "Erreur : la syntaxe `import x as y` est\nvalide.\n"
        },
        {
          "text": "Importe seulement `np` (pas `numpy` au complet)",
          "correct": false,
          "feedback": "Erreur : c'est tout `numpy` qui est importé,\njuste accessible via `np`.\n"
        }
      ],
      "explanation": "Convention de la communauté Python : on\nutilise toujours les mêmes alias pour les\ngrandes bibliothèques scientifiques."
    },
    {
      "id": "q09",
      "difficulty": 1,
      "skills": [
        "bibliotheque-standard"
      ],
      "title": "Bibliothèque standard",
      "statement": "Que signifie « bibliothèque standard de Python » ?",
      "options": [
        {
          "text": "Une norme ISO obligatoire",
          "correct": false,
          "feedback": "Erreur : pas de normalisation officielle.\n"
        },
        {
          "text": "La documentation officielle",
          "correct": false,
          "feedback": "Confusion : la bibliothèque standard est un\n**ensemble de modules**, pas la doc.\n"
        },
        {
          "text": "Les modules livrés avec Python, disponibles sans installation supplémentaire",
          "correct": true,
          "feedback": "Bonne réponse : `math`, `random`, `os`,\n`sys`, `csv`, `json`, `datetime`,\n`urllib`... tous prêts à l'emploi. C'est\nl'une des grandes forces de Python\n(« batteries included »).\n"
        },
        {
          "text": "La bibliothèque physique d'Anthropic",
          "correct": false,
          "feedback": "La bibliothèque standard\nde Python est un ensemble\nde modules logiciels\nmaintenu par la Python\nSoftware Foundation. Elle\nn'a aucun lien avec\nAnthropic ni avec une\ncollection physique.\n"
        }
      ],
      "explanation": "Pour les modules **externes** (numpy, pandas,\nmatplotlib, requests...), il faut installer\navec `pip install nom_du_module`."
    },
    {
      "id": "q10",
      "difficulty": 1,
      "skills": [
        "exemple-pratique"
      ],
      "title": "Exemple complet",
      "statement": "```python\nimport math\nprint(math.sqrt(16))\n```\nQue produit ce code ?",
      "options": [
        {
          "text": "Affiche `16.0`",
          "correct": false,
          "feedback": "Erreur : `sqrt` calcule la **racine**, pas\nl'identité.\n"
        },
        {
          "text": "Affiche `4.0`",
          "correct": true,
          "feedback": "Bonne réponse : `math.sqrt(16)` = 4.0\n(flottant, même pour un carré parfait).\n"
        },
        {
          "text": "Lève une erreur",
          "correct": false,
          "feedback": "Erreur : code valide.\n"
        },
        {
          "text": "Affiche `4`",
          "correct": false,
          "feedback": "Pas tout à fait : `sqrt` renvoie un\n**flottant** (`4.0`), pas un entier.\n"
        }
      ],
      "explanation": "Pour un entier, utiliser `int(math.sqrt(16))`\nou `math.isqrt(16)` (entier directement, sans\npasser par un flottant)."
    },
    {
      "id": "q11",
      "difficulty": 2,
      "skills": [
        "namespace"
      ],
      "title": "Espace de noms",
      "statement": "Pourquoi est-il **déconseillé** d'utiliser\n`from math import *` ?",
      "options": [
        {
          "text": "Parce que c'est trop lent",
          "correct": false,
          "feedback": "Erreur : performance équivalente.\n"
        },
        {
          "text": "Parce que cela importe tous les noms dans le scope global, ce qui peut masquer des variables/fonctions existantes (collisions)",
          "correct": true,
          "feedback": "Bonne réponse : par exemple, si vous\naviez une variable `pow`, elle serait\nécrasée par `math.pow`. Source de bugs\nsubtils.\n"
        },
        {
          "text": "Parce que c'est interdit par Python",
          "correct": false,
          "feedback": "Erreur : possible mais déconseillé.\n"
        },
        {
          "text": "Parce que cela ne fonctionne pas",
          "correct": false,
          "feedback": "Erreur : la syntaxe est valide.\n"
        }
      ],
      "explanation": "Bonne pratique : `import math` (préfixe) ou\n`from math import sqrt, pi` (sélectif).\nÉviter `from x import *` sauf pour des\nmodules conçus pour cela."
    },
    {
      "id": "q12",
      "difficulty": 2,
      "skills": [
        "creer-module"
      ],
      "title": "Créer son module",
      "statement": "Comment créer son propre module\n`mes_outils.py` et l'importer ?",
      "options": [
        {
          "text": "Il faut un mot-clé `module` dans le fichier",
          "correct": false,
          "feedback": "Erreur : aucun mot-clé spécial.\n"
        },
        {
          "text": "Il faut compiler le module avant de l'importer",
          "correct": false,
          "feedback": "Erreur : Python est interprété, pas de\ncompilation explicite.\n"
        },
        {
          "text": "Créer un fichier `mes_outils.py` contenant des fonctions, puis dans un autre fichier du même répertoire : `import mes_outils`",
          "correct": true,
          "feedback": "Bonne réponse : tout fichier `.py` est un\nmodule. Aucune déclaration spéciale n'est\nnécessaire.\n"
        },
        {
          "text": "Il faut publier le module sur PyPI",
          "correct": false,
          "feedback": "Erreur : seulement pour le partage public.\nLocalement, il suffit du fichier.\n"
        }
      ],
      "explanation": "Cette simplicité est l'un des grands atouts\nde Python pour la modularité. Un projet est\nnaturellement organisé en plusieurs fichiers\n`.py`."
    },
    {
      "id": "q13",
      "difficulty": 2,
      "skills": [
        "import-once"
      ],
      "title": "Import une seule fois",
      "statement": "Si l'on écrit `import math` deux fois dans le\nmême programme, que se passe-t-il ?",
      "options": [
        {
          "text": "Cela lève une erreur",
          "correct": false,
          "feedback": "Erreur : pas d'erreur.\n"
        },
        {
          "text": "Le module est dupliqué en mémoire",
          "correct": false,
          "feedback": "Erreur : un seul exemplaire en mémoire.\n"
        },
        {
          "text": "Le module n'est chargé qu'une seule fois ; la deuxième instruction ne fait rien",
          "correct": true,
          "feedback": "Bonne réponse : Python tient un cache des\nmodules déjà chargés (`sys.modules`).\nPerformance optimale.\n"
        },
        {
          "text": "Le module est rechargé à chaque fois (lent)",
          "correct": false,
          "feedback": "Erreur : Python optimise.\n"
        }
      ],
      "explanation": "Pour vraiment recharger un module modifié\n(rare), utiliser `importlib.reload`. Sinon,\nle cache simplifie la vie."
    },
    {
      "id": "q14",
      "difficulty": 2,
      "skills": [
        "random-choice"
      ],
      "title": "Choix aléatoire",
      "statement": "Quelle fonction du module `random` permet de\nchoisir un élément au hasard dans une liste ?",
      "options": [
        {
          "text": "`random.select(liste)`",
          "correct": false,
          "feedback": "Erreur : pas de fonction de ce nom.\n"
        },
        {
          "text": "`random.random(liste)`",
          "correct": false,
          "feedback": "Erreur : `random.random()` renvoie un\nflottant entre 0 et 1, sans paramètre.\n"
        },
        {
          "text": "`random.choice(liste)`",
          "correct": true,
          "feedback": "Bonne réponse : `choice` renvoie un\nélément aléatoire de la liste (chaque\nélément a la même probabilité d'être\nchoisi).\n"
        },
        {
          "text": "`random.pick(liste)`",
          "correct": false,
          "feedback": "Erreur : la fonction n'a pas ce nom.\n"
        }
      ],
      "explanation": "Autres fonctions utiles : `random.choices`\n(avec poids), `random.sample` (sans\nremise), `random.shuffle` (mélange en place)."
    },
    {
      "id": "q15",
      "difficulty": 2,
      "skills": [
        "main"
      ],
      "title": "Bloc principal",
      "statement": "Que signifie l'idiome `if __name__ == \"__main__\":` ?",
      "options": [
        {
          "text": "Que le programme est sans bug",
          "correct": false,
          "feedback": "La présence de cette\ncondition n'apporte\naucune garantie sur la\ncorrection du programme.\nElle distingue uniquement\nun script exécutable d'un\nmodule importable.\n"
        },
        {
          "text": "Que le bloc s'exécute uniquement quand le fichier est lancé directement, pas quand il est importé comme module",
          "correct": true,
          "feedback": "Bonne réponse : `__name__` vaut\n`\"__main__\"` en exécution directe et le\nnom du module en import. Cet idiome\npermet d'avoir des fichiers à la fois\nmodules **et** scripts.\n"
        },
        {
          "text": "Que le programme est en mode débogage",
          "correct": false,
          "feedback": "Aucun mode de débogage\nn'est associé à cette\nconstruction. La variable\n`__name__` reflète le\ncontexte d'exécution :\nscript lancé directement\nou module importé.\n"
        },
        {
          "text": "Que la fonction `main` doit être définie",
          "correct": false,
          "feedback": "Pas tout à fait : `main` n'est qu'une\nconvention, pas obligatoire.\n"
        }
      ],
      "explanation": "Schéma standard pour rendre un fichier\nréutilisable comme module sans déclencher\nses tests/démos lors de l'import."
    },
    {
      "id": "q16",
      "difficulty": 2,
      "skills": [
        "help-doc"
      ],
      "title": "Documentation interactive",
      "statement": "Comment obtenir l'aide d'une fonction d'un\nmodule en mode interactif ?",
      "options": [
        {
          "text": "`help(math.sqrt)`",
          "correct": true,
          "feedback": "Bonne réponse : la fonction native `help`\naffiche la docstring et les annotations\nde la fonction. Très utile en exploration.\n"
        },
        {
          "text": "`man math.sqrt`",
          "correct": false,
          "feedback": "Erreur : `man` est une commande Unix.\n"
        },
        {
          "text": "`info(math.sqrt)`",
          "correct": false,
          "feedback": "Erreur : pas de fonction `info` en Python.\n"
        },
        {
          "text": "`google math.sqrt`",
          "correct": false,
          "feedback": "Aucune commande `google`\nn'existe dans la console\nPython. La documentation\nintégrée s'obtient avec\nla fonction `help`, qui\naffiche directement la\ndocstring associée.\n"
        }
      ],
      "explanation": "Autre forme utile en interactif : `?math.sqrt`\n(en IPython/Jupyter). Et toujours la\ndocumentation officielle :\ndocs.python.org."
    },
    {
      "id": "q17",
      "difficulty": 2,
      "skills": [
        "import-fonction"
      ],
      "title": "Importation sélective",
      "statement": "Quel code utilise `pi` correctement après\n`from math import pi` ?",
      "options": [
        {
          "text": "`math.pi`",
          "correct": false,
          "feedback": "Erreur : avec `from ... import`, on\nn'utilise **pas** le préfixe.\n"
        },
        {
          "text": "`pi`",
          "correct": true,
          "feedback": "Bonne réponse : `pi` est importé\ndirectement dans l'espace de noms local.\nOn peut écrire `2 * pi`.\n"
        },
        {
          "text": "`import.pi`",
          "correct": false,
          "feedback": "Erreur : syntaxe invalide.\n"
        },
        {
          "text": "`from.pi`",
          "correct": false,
          "feedback": "Erreur : syntaxe invalide.\n"
        }
      ],
      "explanation": "`import math` → `math.pi` ; `from math import\npi` → `pi`. Choisir selon ses préférences."
    },
    {
      "id": "q18",
      "difficulty": 2,
      "skills": [
        "conflict-noms"
      ],
      "title": "Conflit de noms",
      "statement": "```python\nfrom math import sqrt\n\ndef sqrt(x):\n    return x ** 0.5\n\nprint(sqrt(16))\n```\nQuelle fonction est appelée ?",
      "options": [
        {
          "text": "La fonction de `math` (4.0)",
          "correct": false,
          "feedback": "Erreur : la définition locale **écrase**\nl'import.\n"
        },
        {
          "text": "Les deux fonctions sont appelées",
          "correct": false,
          "feedback": "Erreur : un seul nom à la fois.\n"
        },
        {
          "text": "La fonction `sqrt` définie localement, qui retourne aussi `4.0` puisqu'elle calcule également la racine carrée",
          "correct": true,
          "feedback": "Bonne réponse : la dernière définition\ngagne. Les deux fonctions calculent la\nmême chose (la racine carrée) et donnent\ndonc le même résultat sur cet exemple,\nmais en général c'est un piège : la\ndéfinition locale masque silencieusement\nl'import.\n"
        },
        {
          "text": "Erreur : conflit de noms",
          "correct": false,
          "feedback": "Erreur : pas d'erreur en Python (qui\nécrase silencieusement).\n"
        }
      ],
      "explanation": "Bonne pratique : éviter de redéfinir des\nnoms importés. Si on doit le faire, l'import\navec préfixe (`import math`) protège."
    },
    {
      "id": "q19",
      "difficulty": 2,
      "skills": [
        "random-seed"
      ],
      "title": "Reproductibilité",
      "statement": "Pourquoi utilise-t-on `random.seed(42)` ?",
      "options": [
        {
          "text": "Pour rendre les tirages plus aléatoires",
          "correct": false,
          "feedback": "Erreur : c'est l'inverse, on les rend\ndéterministes.\n"
        },
        {
          "text": "Pour accélérer le générateur",
          "correct": false,
          "feedback": "Erreur : pas d'effet sur la performance.\n"
        },
        {
          "text": "Pour rendre les tirages reproductibles : avec la même graine, on obtient toujours la même séquence",
          "correct": true,
          "feedback": "Bonne réponse : utile pour le débogage,\nles tests, la reproductibilité\nscientifique.\n"
        },
        {
          "text": "Pour générer le nombre 42",
          "correct": false,
          "feedback": "Erreur : `seed` initialise le générateur\naléatoire, ne génère rien directement.\n"
        }
      ],
      "explanation": "Important : `random` n'est pas\ncryptographiquement sûr (utiliser `secrets`\npour cela). Mais pour les simulations et\njeux, c'est parfait."
    },
    {
      "id": "q20",
      "difficulty": 2,
      "skills": [
        "autres-modules"
      ],
      "title": "Modules variés",
      "statement": "Lequel de ces modules de la bibliothèque\nstandard est utilisé pour manipuler des\n**fichiers JSON** ?",
      "options": [
        {
          "text": "`json`",
          "correct": true,
          "feedback": "Bonne réponse : fonctions principales\n`json.dumps` (objet → chaîne JSON) et\n`json.loads` (chaîne JSON → objet\nPython).\n"
        },
        {
          "text": "`csv`",
          "correct": false,
          "feedback": "C'est pour les fichiers CSV.\n"
        },
        {
          "text": "`math`",
          "correct": false,
          "feedback": "Pour les fonctions mathématiques.\n"
        },
        {
          "text": "`os`",
          "correct": false,
          "feedback": "C'est pour interagir avec le système\nd'exploitation.\n"
        }
      ],
      "explanation": "Modules NSI utiles : `math`, `random`, `csv`,\n`json`, `time`, `datetime`, `os`, `sys`,\n`string`."
    },
    {
      "id": "q21",
      "difficulty": 3,
      "skills": [
        "pip"
      ],
      "title": "Installer un module externe",
      "statement": "Comment installe-t-on un module externe (par\nexemple `numpy`) qui n'est pas dans la\nbibliothèque standard ?",
      "options": [
        {
          "text": "Avec la commande `pip install numpy` (dans le terminal)",
          "correct": true,
          "feedback": "Bonne réponse : `pip` est l'outil\nd'installation officiel de Python.\n`pip install nom` télécharge depuis PyPI\n(Python Package Index).\n"
        },
        {
          "text": "Avec `download numpy` dans Python",
          "correct": false,
          "feedback": "Erreur : pas de fonction de ce nom.\n"
        },
        {
          "text": "Avec `import numpy`",
          "correct": false,
          "feedback": "Erreur : `import` charge un module **déjà\ninstallé**, ne l'installe pas.\n"
        },
        {
          "text": "Il faut le télécharger manuellement et le copier",
          "correct": false,
          "feedback": "C'était possible historiquement, mais\n`pip` automatise tout cela.\n"
        }
      ],
      "explanation": "`pip` gère aussi les dépendances entre\nmodules. Pour un projet, un fichier\n`requirements.txt` listant les dépendances\nfacilite la reproductibilité."
    },
    {
      "id": "q22",
      "difficulty": 3,
      "skills": [
        "structure-package"
      ],
      "title": "Package",
      "statement": "Quelle est la différence entre un **module** et\nun **package** en Python ?",
      "options": [
        {
          "text": "Un module est plus rapide",
          "correct": false,
          "feedback": "Erreur : pas de différence de\nperformance.\n"
        },
        {
          "text": "Un package est un module compilé",
          "correct": false,
          "feedback": "Erreur : pas de compilation Python directe.\n"
        },
        {
          "text": "Aucune",
          "correct": false,
          "feedback": "Erreur : ce sont deux notions différentes.\n"
        },
        {
          "text": "Un module est un fichier `.py` ; un package est un répertoire contenant plusieurs modules (et un fichier `__init__.py`)",
          "correct": true,
          "feedback": "Bonne réponse : `numpy`, `pandas`, etc.\nsont des packages (répertoires). On\naccède à leurs sous-modules avec\n`numpy.linalg`, etc.\n"
        }
      ],
      "explanation": "En NSI Première, on travaille surtout avec\ndes modules simples. Les packages sont une\nstructuration plus avancée pour les gros\nprojets."
    },
    {
      "id": "q23",
      "difficulty": 3,
      "skills": [
        "shadowing"
      ],
      "title": "Pollution du namespace",
      "statement": "Pourquoi le code suivant peut-il être\nproblématique ?\n```python\nfrom random import *\nfrom math import *\n```",
      "options": [
        {
          "text": "Parce que les deux modules peuvent avoir des fonctions de même nom (par exemple `pow`), et le second import écrase silencieusement le premier",
          "correct": true,
          "feedback": "Bonne réponse : conflit silencieux,\nsource de bugs très difficiles à\ndiagnostiquer. À éviter dans tout code\nsérieux.\n"
        },
        {
          "text": "Parce que c'est trop lent",
          "correct": false,
          "feedback": "Erreur : performance acceptable.\n"
        },
        {
          "text": "Parce que l'on ne peut pas importer plusieurs modules",
          "correct": false,
          "feedback": "Erreur : on peut importer autant qu'on veut.\n"
        },
        {
          "text": "Parce que `math` doit être importé avant `random`",
          "correct": false,
          "feedback": "Erreur : aucun ordre imposé.\n"
        }
      ],
      "explanation": "Maxime PEP 20 : « Explicit is better than\nimplicit. » Préférer les imports explicites\npour la traçabilité."
    },
    {
      "id": "q24",
      "difficulty": 3,
      "skills": [
        "bonne-pratique"
      ],
      "title": "Ordre des imports",
      "statement": "Dans un fichier Python bien organisé, où\nplacer les `import` ?",
      "options": [
        {
          "text": "Dans une fonction `main`",
          "correct": false,
          "feedback": "Possible (chargement paresseux) mais\nexceptionnel. Convention : en haut.\n"
        },
        {
          "text": "À la fin du fichier",
          "correct": false,
          "feedback": "Erreur : tous les noms importés ne seraient\npas disponibles avant.\n"
        },
        {
          "text": "N'importe où dans le fichier",
          "correct": false,
          "feedback": "Techniquement possible, mais déconseillé.\n"
        },
        {
          "text": "En haut du fichier, regroupés (standards / externes / locaux)",
          "correct": true,
          "feedback": "Bonne réponse : convention PEP 8 :\nd'abord les imports standards (`math`,\n`os`...), puis les externes (`numpy`,\n`pandas`...), puis les modules locaux du\nprojet, séparés par une ligne vide.\n"
        }
      ],
      "explanation": "Convention de lecture : voir tout de suite\nles dépendances en haut du fichier.\nBeaucoup d'éditeurs (et d'analyseurs\nstatiques) vérifient cet ordre."
    },
    {
      "id": "q25",
      "difficulty": 3,
      "skills": [
        "synthese"
      ],
      "title": "Synthèse",
      "statement": "Parmi les affirmations suivantes, laquelle est\n**fausse** ?",
      "options": [
        {
          "text": "`from math import pi` importe la constante `pi` sans préfixe",
          "correct": false,
          "feedback": "Vrai : importation sélective.\n"
        },
        {
          "text": "La bibliothèque standard de Python contient des modules pour les fichiers, le réseau, les dates, le hasard, etc.",
          "correct": false,
          "feedback": "Vrai : « batteries included », l'une des\nforces de Python.\n"
        },
        {
          "text": "Tout module importé est systématiquement rechargé à chaque exécution du programme",
          "correct": true,
          "feedback": "Faux (donc bonne réponse) : Python met\nen cache les modules dans `sys.modules`.\nUn module n'est chargé **qu'une seule\nfois** par exécution, même si on l'importe\ndans plusieurs fichiers.\n"
        },
        {
          "text": "`import math` rend les fonctions accessibles via le préfixe `math.`",
          "correct": false,
          "feedback": "Vrai : c'est le rôle de `import`.\n"
        }
      ],
      "explanation": "Le cache de modules garantit la cohérence\n(un seul exemplaire en mémoire) et la\nperformance."
    },
    {
      "id": "q26",
      "difficulty": 2,
      "skills": [
        "random",
        "randint"
      ],
      "title": "random.random et random.randint",
      "statement": "Quelle est la différence entre `random.random()` et\n`random.randint(a, b)` ?",
      "options": [
        {
          "text": "Les deux renvoient un entier compris entre 0 et 1",
          "correct": false,
          "feedback": "Erreur : la fonction `random.random()` renvoie un\nflottant, pas un entier. Et `randint(a, b)` peut\nrenvoyer n'importe quel entier de l'intervalle, pas\nseulement $0$ ou $1$.\n"
        },
        {
          "text": "`random.random()` renvoie un flottant tiré uniformément dans $[0\\,;\\, 1[$ ; `random.randint(a, b)` renvoie un entier tiré uniformément dans $[a\\,;\\, b]$ (bornes incluses)",
          "correct": true,
          "feedback": "Bonne réponse : `random.random()` produit un\nflottant inférieur à $1$, tandis que\n`random.randint(a, b)` est l'unique fonction du\nmodule à inclure les **deux** bornes (alors que\nla plupart des intervalles Python excluent la\nborne droite).\n"
        },
        {
          "text": "La fonction `random.randint(a, b)` exclut la borne `b`",
          "correct": false,
          "feedback": "Erreur : c'est précisément la particularité de\n`randint` parmi les fonctions du module : la borne\ndroite est **incluse**. Pour exclure la borne, il\nfaudrait utiliser `random.randrange(a, b)`.\n"
        },
        {
          "text": "`random.random()` renvoie l'heure courante ; `random.randint` lit la mémoire",
          "correct": false,
          "feedback": "Erreur : aucune des deux fonctions n'est liée à\nl'heure ni à la mémoire. Elles produisent toutes\ndeux des valeurs pseudo-aléatoires.\n"
        }
      ],
      "explanation": "Pour mémoriser : `random.random()` $\\to [0\\,;\\, 1[$\n(flottant) ; `random.randint(a, b)` $\\to [a\\,;\\, b]$\n(entier) ; `random.randrange(a, b)` $\\to [a\\,;\\, b[$\n(entier) ; `random.choice(seq)` $\\to$ un élément de\nla séquence. Pour la reproductibilité d'un tirage,\nfixer `random.seed(...)` au début du programme."
    },
    {
      "id": "q27",
      "difficulty": 2,
      "skills": [
        "math",
        "fonctions-courantes"
      ],
      "title": "Fonctions du module math",
      "statement": "Parmi les expressions suivantes, laquelle ne renvoie\n**pas** $5$ après l'instruction `import math` ?",
      "options": [
        {
          "text": "`math.ceil(4.3)`",
          "correct": false,
          "feedback": "La fonction `ceil` arrondit vers le haut. Pour\n$4{,}3$, le résultat est $5$.\n"
        },
        {
          "text": "`math.log(100)`",
          "correct": true,
          "feedback": "Bonne réponse : `math.log` calcule le logarithme\n**naturel** par défaut, pas le logarithme\ndécimal. On a $\\ln(100) \\approx 4{,}605$, et non\n$5$. Pour le logarithme en base $10$, il faut\nécrire `math.log10(100)` ou\n`math.log(100, 10)`.\n"
        },
        {
          "text": "`math.sqrt(25)`",
          "correct": false,
          "feedback": "La racine carrée de $25$ vaut bien $5$. Cette\nexpression renvoie donc $5$ (au flottant\n$5{,}0$ près).\n"
        },
        {
          "text": "`math.floor(5.7)`",
          "correct": false,
          "feedback": "La fonction `floor` arrondit vers le bas (partie\nentière inférieure). Pour $5{,}7$, le résultat\nest $5$.\n"
        }
      ],
      "explanation": "Quelques fonctions usuelles du module `math` :\n`sqrt` (racine carrée), `floor` et `ceil` (arrondis\nbas et haut), `log` (logarithme népérien),\n`log10` (logarithme décimal), `exp` (exponentielle),\n`sin`/`cos`/`tan` (trigonométrie en radians).\nConstantes : `math.pi`, `math.e`, `math.inf`."
    },
    {
      "id": "q28",
      "difficulty": 2,
      "skills": [
        "time",
        "mesure-duree"
      ],
      "title": "Mesurer une durée d'exécution",
      "statement": "On souhaite mesurer la durée d'exécution d'une\nportion de code. Quelle structure utilise le module\n`time` de manière correcte ?",
      "options": [
        {
          "text": "```python\nimport time\nduree = time.mesure(code)\n```\n",
          "correct": false,
          "feedback": "Erreur : aucune fonction `time.mesure` n'existe.\nPour mesurer du code de manière plus fine, on\nutilise plutôt le module dédié `timeit`.\n"
        },
        {
          "text": "```python\nimport time\nduree = time.now()\n```\n",
          "correct": false,
          "feedback": "Erreur : la fonction `time.now()` n'existe pas.\nCette confusion vient peut-être du module\n`datetime`, qui propose `datetime.now()` pour\nobtenir un objet date complet.\n"
        },
        {
          "text": "```python\nimport time\nduree = time.sleep(10)\n```\n",
          "correct": false,
          "feedback": "Erreur : `time.sleep(10)` met le programme en\npause pendant $10$ secondes. Cette fonction ne\nmesure rien : elle attend le délai indiqué et\nrenvoie `None`.\n"
        },
        {
          "text": "```python\nimport time\ndebut = time.time()\n# ... code à mesurer ...\nduree = time.time() - debut\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : `time.time()` renvoie le nombre\nde secondes écoulées depuis le $1^{\\text{er}}$\njanvier $1970$. La différence entre deux\nappels donne la durée écoulée en secondes\n(avec une précision de l'ordre de la\nmicroseconde sur les systèmes modernes).\n"
        }
      ],
      "explanation": "Pour des mesures plus précises ou de très courtes\ndurées, préférer `time.perf_counter()` à\n`time.time()`. Pour comparer la performance de\nplusieurs implémentations, le module `timeit` est\nadapté : il exécute le code plusieurs fois et\natténue les fluctuations."
    }
  ]
}