{
  "chapter": {
    "id": "modularite-paradigmes",
    "level": "terminale",
    "theme": "Programmation",
    "title": "Modularité et paradigmes",
    "description": "Modularité d'un programme par séparation en modules\ncohérents, paradigmes de programmation (impératif,\nfonctionnel, objet), notion d'abstraction, intérêt\nde la décomposition pour la lisibilité et la\nréutilisation du code.",
    "parties": [
      {
        "id": "modularite",
        "title": "Modularité, modules et bibliothèques"
      },
      {
        "id": "paradigmes",
        "title": "Paradigmes de programmation"
      }
    ],
    "prerequisites": [],
    "references": []
  },
  "questions": [
    {
      "id": "q01",
      "difficulty": 1,
      "skills": [
        "definition-modularite"
      ],
      "title": "Modularité d'un programme",
      "partie": "modularite",
      "statement": "Qu'appelle-t-on la **modularité** d'un\nprogramme ?",
      "options": [
        {
          "text": "Sa qualité esthétique",
          "correct": false,
          "feedback": "La modularité est une propriété\nstructurelle objective, et non un\njugement subjectif sur l'apparence\ndu code.\n"
        },
        {
          "text": "Sa taille mesurée en nombre de lignes",
          "correct": false,
          "feedback": "La taille en lignes ne reflète pas\nla modularité d'un programme. Un\nprogramme court peut être très peu\nmodulaire, et inversement.\n"
        },
        {
          "text": "Sa rapidité d'exécution",
          "correct": false,
          "feedback": "La rapidité d'exécution est une\npropriété distincte. Un programme\nmodulaire peut être rapide ou\nlent ; les deux qualités sont\nindépendantes.\n"
        },
        {
          "text": "Sa décomposition en modules cohérents",
          "correct": true,
          "feedback": "Un programme modulaire est plus\nlisible, plus testable et plus\nfacile à maintenir. La modularité\nest l'un des piliers du génie\nlogiciel.\n"
        }
      ],
      "explanation": "Découper un programme en modules permet de confier à chacun une tâche précise, de le tester isolément et de le réutiliser ailleurs. Un module bien conçu dépend le moins possible des détails internes des autres."
    },
    {
      "id": "q02",
      "difficulty": 1,
      "skills": [
        "paradigme-imperatif"
      ],
      "title": "Paradigme impératif",
      "partie": "paradigmes",
      "statement": "Qu'est-ce que le **paradigme impératif**\nen programmation ?",
      "options": [
        {
          "text": "Une simple variante du paradigme fonctionnel",
          "correct": false,
          "feedback": "Les paradigmes impératif et\nfonctionnel sont au contraire\ntrès différents : ils s'opposent\nnotamment sur la place accordée à\nla mutation des variables.\n"
        },
        {
          "text": "Un style de programmation interdit par la loi",
          "correct": false,
          "feedback": "Cette interprétation littérale du\nmot « impératif » est sans rapport\navec son sens informatique. Aucun\nparadigme de programmation n'est\ninterdit par une loi.\n"
        },
        {
          "text": "Un paradigme inventé en $2020$",
          "correct": false,
          "feedback": "Le paradigme impératif est très\nancien : il est associé aux\ndébuts mêmes de la programmation\ndans les années $1950$.\n"
        },
        {
          "text": "Des instructions dans l'ordre modifiant l'état",
          "correct": true,
          "feedback": "C'est le style de programmation le\nplus répandu, présent en C, en\nPascal, en Java, et partiellement\nen Python. Il consiste à décrire\n« comment faire » étape par\nétape, à la manière d'une\nrecette.\n"
        }
      ],
      "explanation": "Caractéristiques de ce paradigme :\nutilisation de variables modifiables,\nde boucles et d'instructions\nséquentielles. Cette approche est\nhistoriquement liée à l'architecture\nde von Neumann."
    },
    {
      "id": "q03",
      "difficulty": 1,
      "skills": [
        "paradigme-fonctionnel"
      ],
      "title": "Paradigme fonctionnel",
      "partie": "paradigmes",
      "statement": "Qu'est-ce que le **paradigme fonctionnel** en programmation ?",
      "options": [
        {
          "text": "Un paradigme dédié à la gestion des erreurs",
          "correct": false,
          "feedback": "La gestion des erreurs n'est pas\nle sujet propre du paradigme\nfonctionnel. Celui-ci concerne\nplutôt la manière de structurer\nles calculs autour de fonctions\nsans effet de bord.\n"
        },
        {
          "text": "Évaluer des fonctions sans effet de bord",
          "correct": true,
          "feedback": "Les langages purement\nfonctionnels les plus connus sont\nHaskell, Lisp et OCaml. Python\npermet aussi d'adopter certains\naspects fonctionnels, par exemple\navec les expressions `lambda`,\nou les fonctions `map` et\n`filter`.\n"
        },
        {
          "text": "Tout simplement un programme qui fonctionne correctement",
          "correct": false,
          "feedback": "Cette interprétation littérale du\nmot « fonctionnel » est trompeuse.\nEn programmation, le paradigme\nfonctionnel renvoie à un style\nprécis, fondé sur l'évaluation de\nfonctions sans effet de bord.\n"
        },
        {
          "text": "Le même paradigme que l'impératif",
          "correct": false,
          "feedback": "Les deux paradigmes s'opposent\nsur des points fondamentaux,\nnotamment la mutation des\nvariables et la présence\nd'effets de bord.\n"
        }
      ],
      "explanation": "Avantages : un code plus prévisible\n(sans effets de bord cachés), un\nparallélisme facilité, et une plus\ngrande facilité de test. En\ncontrepartie, l'apprentissage peut\nparaître exigeant pour quelqu'un\nhabitué au style impératif."
    },
    {
      "id": "q04",
      "difficulty": 1,
      "skills": [
        "paradigme-objet"
      ],
      "title": "Paradigme objet",
      "partie": "paradigmes",
      "statement": "Qu'est-ce que la **programmation orientée objet** ?",
      "options": [
        {
          "text": "Le fait de coder en utilisant des objets physiques",
          "correct": false,
          "feedback": "Cette interprétation littérale est\nsans rapport avec le sens\ninformatique. Les objets en\nprogrammation orientée objet sont\ndes entités logicielles\nabstraites, pas des objets\nphysiques.\n"
        },
        {
          "text": "Un paradigme aujourd'hui obsolète",
          "correct": false,
          "feedback": "Au contraire, la programmation\norientée objet reste très utilisée\ndans le monde du logiciel, et\nnotamment dans les grands projets\nindustriels.\n"
        },
        {
          "text": "Une bibliothèque graphique",
          "correct": false,
          "feedback": "Le paradigme objet est une manière\nd'organiser le code en général,\net non une bibliothèque\nparticulière dédiée à\nl'affichage.\n"
        },
        {
          "text": "Structurer le code autour d'objets",
          "correct": true,
          "feedback": "Java, C++, Python et Ruby sont\ndes langages très utilisés en\nprogrammation orientée objet. Au\nprogramme officiel : la définition\nd'une classe, ses attributs, ses\nméthodes, et la création\nd'instances.\n"
        }
      ],
      "explanation": "La programmation orientée objet a été\nformalisée par Alan Kay dans le\nlangage Smalltalk en $1972$. Elle\nest particulièrement adaptée pour\nmodéliser des entités du monde réel\n(Voiture, Personne, Compte\nbancaire). Pour des problèmes\nsimples, elle peut toutefois\nalourdir inutilement le code."
    },
    {
      "id": "q05",
      "difficulty": 1,
      "skills": [
        "abstraction"
      ],
      "title": "Abstraction",
      "partie": "modularite",
      "statement": "Qu'appelle-t-on **abstraction** en\nprogrammation ?",
      "options": [
        {
          "text": "Un paradigme de programmation particulier",
          "correct": false,
          "feedback": "L'abstraction est plus large\nqu'un paradigme : elle traverse\ntous les paradigmes (impératif,\nfonctionnel, objet) et fait\npartie du vocabulaire général de\nla programmation.\n"
        },
        {
          "text": "Une notion appartenant aux mathématiques",
          "correct": false,
          "feedback": "Le mot « abstraction » a un sens\nprécis en mathématiques, mais on\nparle ici de son sens\ninformatique : cacher les détails\nd'une implémentation derrière une\ninterface.\n"
        },
        {
          "text": "Cacher les détails derrière une interface",
          "correct": true,
          "feedback": "Par exemple, on utilise\n`len(liste)` sans avoir besoin de\nconnaître l'implémentation de\ncette fonction. L'abstraction est\nle fondement même de la\nmodularité.\n"
        },
        {
          "text": "Une obligation imposée par la loi",
          "correct": false,
          "feedback": "L'abstraction est un principe de\nconception, sans rapport avec une\nquelconque obligation légale.\n"
        }
      ],
      "explanation": "Tous les langages offrent des\nmécanismes d'abstraction : les\nfonctions, les modules, les classes,\nles types abstraits. Un bon design\nlogiciel exploite ces mécanismes au\nmaximum pour produire un code\nlisible et maintenable."
    },
    {
      "id": "q06",
      "difficulty": 1,
      "skills": [
        "decoupage"
      ],
      "title": "Pourquoi découper un programme ?",
      "partie": "modularite",
      "statement": "Pourquoi **découper un programme** en\nplusieurs fonctions ou modules ?",
      "options": [
        {
          "text": "Pour la lisibilité, les tests et la maintenance",
          "correct": true,
          "feedback": "Un programme découpé en petites\nunités cohérentes est nettement\nplus facile à comprendre, à\ntester et à faire évoluer dans\nle temps.\n"
        },
        {
          "text": "Pour gagner quelques secondes lors de la compilation",
          "correct": false,
          "feedback": "Le gain en compilation, s'il\nexiste, est marginal et ne\nconstitue pas l'objectif\nprincipal du découpage en\nmodules.\n"
        },
        {
          "text": "Pour rendre le code plus complexe",
          "correct": false,
          "feedback": "C'est exactement l'inverse. Le\ndécoupage vise à **simplifier**\nle code en le structurant en\npetites unités intelligibles.\n"
        },
        {
          "text": "Aucune raison particulière ne le justifie",
          "correct": false,
          "feedback": "Le découpage répond au contraire à\nplusieurs objectifs concrets,\ncomme expliqué dans la bonne\nréponse.\n"
        }
      ],
      "explanation": "Une maxime classique du génie\nlogiciel résume bien cette idée :\n« une fonction, une responsabilité ».\nSi une fonction effectue plusieurs\ntâches distinctes, mieux vaut la\nscinder en autant de fonctions que\nde responsabilités identifiées."
    },
    {
      "id": "q07",
      "difficulty": 1,
      "skills": [
        "exemple-langages"
      ],
      "title": "Paradigmes du langage Python",
      "partie": "modularite",
      "statement": "Quel paradigme **dominant** caractérise\nle langage Python ?",
      "options": [
        {
          "text": "Python est multi-paradigmes",
          "correct": true,
          "feedback": "Python permet de mélanger\nlibrement les différents styles\nde programmation. C'est un\nlangage très flexible, qui laisse\nau programmeur le soin de\nchoisir l'approche la plus\nadaptée au problème traité.\n"
        },
        {
          "text": "Uniquement le paradigme objet",
          "correct": false,
          "feedback": "Python est certes très orienté\nobjet en interne (toute valeur\nest un objet), mais il accepte\nparfaitement d'autres styles de\nprogrammation, à commencer par\nle style impératif.\n"
        },
        {
          "text": "Uniquement le paradigme impératif",
          "correct": false,
          "feedback": "Python ne se limite pas au style\nimpératif : il offre des outils\nfonctionnels (`lambda`, `map`,\ncompréhensions) et un système\nobjet complet.\n"
        },
        {
          "text": "Strictement le seul paradigme fonctionnel",
          "correct": false,
          "feedback": "Python n'est pas un langage\npurement fonctionnel. Il accepte\nla mutation des variables et les\neffets de bord, qui sont au\ncontraire évités en\nprogrammation purement\nfonctionnelle.\n"
        }
      ],
      "explanation": "Python est un langage multi-paradigmes\npar conception. De nombreux langages\nmodernes le sont également\n(JavaScript, Scala, Kotlin). Cette\nflexibilité permet de choisir le\nmeilleur outil pour chaque situation."
    },
    {
      "id": "q08",
      "difficulty": 1,
      "skills": [
        "import-modules"
      ],
      "title": "Importer un module",
      "partie": "modularite",
      "statement": "En Python, comment **importe-t-on** des\nfonctions définies dans un module\n`outils.py` situé à côté du fichier\nprincipal ?",
      "options": [
        {
          "text": "Avec une directive spéciale `include outils.py` en tête",
          "correct": false,
          "feedback": "La directive `include` existe en\nC ou en C++, mais pas en\nPython. Le mécanisme d'import\nest différent.\n"
        },
        {
          "text": "Avec `import outils` ou `from outils import fonction`",
          "correct": true,
          "feedback": "Ce sont les deux syntaxes standard. Avec la première, les fonctions s'utilisent sous la forme `outils.fonction` ; la seconde permet d'utiliser directement la fonction importée, sans préfixe.\n"
        },
        {
          "text": "Avec l'instruction `use outils`",
          "correct": false,
          "feedback": "La syntaxe `use` n'existe pas en\nPython. C'est le mot-clé\n`import` qu'il faut utiliser.\n"
        },
        {
          "text": "Aucune syntaxe ne permet ce type d'import",
          "correct": false,
          "feedback": "Python propose au contraire un\nmécanisme d'import très complet,\ncomme indiqué dans la bonne\nréponse.\n"
        }
      ],
      "explanation": "La modularité en Python repose sur les modules, qui sont de simples fichiers d'extension `.py` : un fichier placé à côté du programme principal s'importe par son nom, sans l'extension."
    },
    {
      "id": "q09",
      "difficulty": 1,
      "skills": [
        "reutilisation"
      ],
      "title": "Avantage de la réutilisation",
      "partie": "modularite",
      "statement": "Quel est le **principal avantage** de la\nréutilisation de code déjà écrit ?",
      "options": [
        {
          "text": "Le code s'exécute plus rapidement",
          "correct": false,
          "feedback": "La rapidité d'exécution n'est\npas systématiquement améliorée\npar la réutilisation. Une\nbibliothèque générique peut\nparfois être plus lente qu'une\nimplémentation spécialisée.\n"
        },
        {
          "text": "On code plus vite, avec moins de bugs",
          "correct": true,
          "feedback": "Plutôt que de tout réinventer, on\ns'appuie sur du code existant,\nqu'il s'agisse de la\nbibliothèque standard du langage\nou de bibliothèques externes\nreconnues. Cela permet un effet\nd'échelle : un même code testé\nsert à de nombreux programmes.\n"
        },
        {
          "text": "Aucun avantage particulier",
          "correct": false,
          "feedback": "La réutilisation apporte au\ncontraire des bénéfices\nimportants, comme expliqué dans\nla bonne réponse.\n"
        },
        {
          "text": "Le code occupe moins d'espace",
          "correct": false,
          "feedback": "La place occupée n'est pas le\ncritère principal. La\nréutilisation peut même\naugmenter la taille du programme\nsi la bibliothèque utilisée est\nvolumineuse.\n"
        }
      ],
      "explanation": "Une bonne pratique consiste à se\nfamiliariser avec la bibliothèque\nstandard de son langage avant\nd'écrire du code soi-même. Beaucoup\nde problèmes ont déjà une solution\néprouvée disponible."
    },
    {
      "id": "q10",
      "difficulty": 1,
      "skills": [
        "trace-fonction"
      ],
      "title": "Décomposition typique",
      "partie": "modularite",
      "statement": "Pour calculer la moyenne d'une liste\nde notes lue dans un fichier au format\nCSV, quelle décomposition est la **plus propre** ?",
      "options": [
        {
          "text": "N'utiliser aucune fonction",
          "correct": false,
          "feedback": "Écrire un programme entier sans\naucune fonction est une mauvaise\npratique. Le découpage en\nfonctions reste essentiel à la\nlisibilité.\n"
        },
        {
          "text": "Tout placer dans une seule fonction",
          "correct": false,
          "feedback": "Une fonction qui mélange lecture,\ncalcul et affichage est plus\ndifficile à tester et à\nréutiliser. Mieux vaut séparer\nces responsabilités.\n"
        },
        {
          "text": "Trois fonctions distinctes (lire, calculer, afficher)",
          "correct": true,
          "feedback": "Chaque fonction a alors une\nresponsabilité claire et unique.\nChacune peut être testée\nindépendamment et réutilisée\nailleurs dans le programme ou\ndans un autre projet.\n"
        },
        {
          "text": "Une seule fonction qui ne fait qu'un appel à `print`",
          "correct": false,
          "feedback": "Cette décomposition est trop\nminimaliste. Aucune des\nopérations principales (lecture,\ncalcul) n'est isolée dans sa\npropre fonction.\n"
        }
      ],
      "explanation": "Le principe de **séparation des préoccupations** consiste à isoler\nles entrées-sorties, le calcul, et\nla présentation des résultats. C'est\nune architecture classique, simple\net robuste."
    },
    {
      "id": "q11",
      "difficulty": 2,
      "skills": [
        "organisation-modules",
        "couplage"
      ],
      "title": "Deux modules qui s'importent mutuellement",
      "partie": "modularite",
      "statement": "Dans un projet, le module `calculs.py`\ncommence par `import affichage` pour\nmontrer ses résultats à l'écran, et le\nmodule `affichage.py` commence par\n`import calculs` pour obtenir les valeurs\nà afficher. Quel défaut de conception ce\nchoix révèle-t-il ?",
      "options": [
        {
          "text": "Une dépendance circulaire, qui soude les deux modules l'un à l'autre",
          "correct": true,
          "feedback": "Bonne réponse : deux modules qui\ns'importent l'un l'autre forment en\nréalité un seul bloc. Impossible de\ntester `calculs` seul, de le réutiliser\ndans un autre projet ou de remplacer\n`affichage` sans toucher à `calculs`.\nC'est le couplage fort que la\nconception modulaire cherche à éviter :\n`calculs` doit se contenter de renvoyer\nses résultats, et c'est `affichage` (ou\nle programme principal) qui les montre.\n"
        },
        {
          "text": "Aucun défaut, car Python accepte les imports dans les deux sens",
          "correct": false,
          "feedback": "Erreur : Python charge bien les deux\nfichiers, mais la conception reste\ndéfectueuse, car aucun des deux modules\nne peut plus vivre séparément.\nL'exécution peut même échouer : si\n`affichage.py` écrit\n`from calculs import moyenne`, le\nprogramme s'arrête sur `ImportError`,\ncar `calculs` n'a pas fini de se charger\nau moment où `affichage` réclame sa\nfonction.\n"
        },
        {
          "text": "Un doublon de code, car chaque module recopie les fonctions de l'autre",
          "correct": false,
          "feedback": "Erreur : `import` ne recopie aucun\ncode. Chaque fonction n'existe qu'une\nfois, dans le fichier qui la définit.\nLe défaut n'est pas la duplication mais\nla dépendance mutuelle, qui attache les\ndeux modules l'un à l'autre.\n"
        },
        {
          "text": "Une perte de temps, car chaque appel de fonction recharge l'autre module",
          "correct": false,
          "feedback": "Erreur : un module n'est chargé qu'une\nseule fois, lors de son premier\n`import` ; les appels de fonctions qui\nsuivent ne rechargent rien. Le problème\nn'est pas la vitesse d'exécution mais\nl'organisation du programme, dans\nlaquelle les deux modules dépendent\nl'un de l'autre.\n"
        }
      ],
      "explanation": "Les dépendances entre modules doivent\nformer une hiérarchie sans cycle : un\nmodule de bas niveau (calculs, structures\nde données) ignore ceux qui l'utilisent\n(affichage, programme principal). Un module\nqui ne dépend que de la bibliothèque\nstandard est le plus simple à tester et à\nréutiliser."
    },
    {
      "id": "q12",
      "difficulty": 2,
      "skills": [
        "acces-attribut"
      ],
      "title": "Accéder à un attribut",
      "partie": "paradigmes",
      "statement": "Soit l'instance\n`v = Voiture(\"Peugeot\", 2020)`. Comment\naccède-t-on à l'attribut `marque` de\ncet objet ?",
      "options": [
        {
          "text": "Avec la notation `v::marque`",
          "correct": false,
          "feedback": "Le double deux-points est\nutilisé en C++ (résolution de\nportée), mais pas en Python.\n"
        },
        {
          "text": "Avec la notation `v[marque]`",
          "correct": false,
          "feedback": "Les crochets servent à indexer\nune liste ou un dictionnaire,\net non à accéder à l'attribut\nd'un objet.\n"
        },
        {
          "text": "Avec la notation `v.marque`",
          "correct": true,
          "feedback": "La notation pointée permet\nd'accéder aussi bien aux\nattributs qu'aux méthodes d'un\nobjet. C'est la syntaxe\nstandard en Python.\n"
        },
        {
          "text": "Avec la notation `v->marque`",
          "correct": false,
          "feedback": "La flèche `->` est utilisée en\nC ou en C++, mais pas en\nPython.\n"
        }
      ],
      "explanation": "La notation `objet.attribut`\npermet de lire ou de modifier un\nattribut. La notation\n`objet.methode(...)` permet\nd'appeler une méthode définie sur\nl'objet."
    },
    {
      "id": "q13",
      "difficulty": 2,
      "skills": [
        "fonction-pure"
      ],
      "title": "Fonction pure",
      "partie": "paradigmes",
      "statement": "Qu'est-ce qu'une **fonction pure**, au\nsens du paradigme fonctionnel ?",
      "options": [
        {
          "text": "Une fonction qui ne prend aucun paramètre",
          "correct": false,
          "feedback": "Le nombre de paramètres n'a\naucun rapport avec la pureté\nd'une fonction. Une fonction\npure peut prendre zéro, un ou\nplusieurs paramètres.\n"
        },
        {
          "text": "Une fonction écrite dans un langage mathématique",
          "correct": false,
          "feedback": "Cette description est trop\nvague. Une fonction pure se\ndéfinit précisément par\nl'absence d'effet de bord et\npar sa déterministicité, et non\npar son expression dans un\nlangage particulier.\n"
        },
        {
          "text": "Une fonction qui ne contient aucun bug",
          "correct": false,
          "feedback": "La pureté n'a aucun rapport\navec l'absence de bugs. Une\nfonction pure peut très bien\nêtre incorrecte ; inversement,\nune fonction avec effets de\nbord peut être correcte.\n"
        },
        {
          "text": "Même résultat pour mêmes paramètres, sans effet de bord",
          "correct": true,
          "feedback": "Ce type de fonction est\nprévisible, facilement\ntestable, et permet une\nparallélisation aisée. Un\nexemple : `def carre(x): return\nx * x`. À l'inverse, une\nfonction comme\n`def lire_fichier(f)` n'est\npas pure, car elle effectue\nune opération\nd'entrée-sortie.\n"
        }
      ],
      "explanation": "Un avantage important des\nfonctions pures est qu'elles\nautorisent la **mémoïsation**, qui\nconsiste à mettre en cache les\nrésultats déjà calculés. Ces\nfonctions facilitent aussi le\nraisonnement mathématique sur le\nprogramme."
    },
    {
      "id": "q14",
      "difficulty": 2,
      "skills": [
        "responsabilite-unique"
      ],
      "title": "Une fonction, une responsabilité",
      "partie": "modularite",
      "statement": "Que recommande le principe\n« **une fonction, une responsabilité** » ?",
      "options": [
        {
          "text": "Un programme ne doit posséder qu'une seule fonction",
          "correct": false,
          "feedback": "Cette interprétation est\nincorrecte. Un programme\ncontient en général de\nnombreuses fonctions, chacune\nayant sa responsabilité\npropre.\n"
        },
        {
          "text": "Chaque fichier doit contenir une seule fonction",
          "correct": false,
          "feedback": "Un module peut tout à fait\ncontenir plusieurs fonctions\nliées à un même thème. Ce\nprincipe ne porte pas sur\nl'organisation des fichiers.\n"
        },
        {
          "text": "Chaque fonction doit prendre exactement un seul paramètre",
          "correct": false,
          "feedback": "Le nombre de paramètres n'a\naucun rapport avec ce\nprincipe, qui concerne la\ntâche accomplie par la\nfonction.\n"
        },
        {
          "text": "Chaque fonction accomplit une seule tâche",
          "correct": true,
          "feedback": "Ce principe est l'un des piliers\nde la modularité. Une fonction\nà responsabilité unique est\nplus fiable, plus lisible et\nplus facile à tester. Si l'on\nne peut pas décrire une\nfonction en une phrase courte,\nil vaut mieux la découper.\n"
        }
      ],
      "explanation": "Si une fonction `traiter` lit un\nfichier, effectue des calculs et\nécrit le résultat, mieux vaut la\nscinder en trois fonctions\ndistinctes, chacune dédiée à une\nseule responsabilité."
    },
    {
      "id": "q15",
      "difficulty": 2,
      "skills": [
        "interface"
      ],
      "title": "Interface d'un module",
      "partie": "modularite",
      "statement": "Que désigne l'**interface** d'un\nmodule ou d'une fonction ?",
      "options": [
        {
          "text": "Uniquement la documentation du module",
          "correct": false,
          "feedback": "La documentation décrit\nl'interface, mais l'interface\nelle-même est un concept plus\nlarge : elle inclut aussi la\nsignature effective des\nfonctions et leur\ncomportement.\n"
        },
        {
          "text": "Les points d'accès publics du module",
          "correct": true,
          "feedback": "L'interface joue le rôle d'un\ncontrat public. Tant que ce\ncontrat est respecté, on peut\nmodifier l'implémentation sans\nimpacter les utilisateurs du\nmodule.\n"
        },
        {
          "text": "Le code source du module",
          "correct": false,
          "feedback": "Le code source représente\nl'**implémentation** du module,\nc'est-à-dire la manière dont il\nfonctionne en interne. C'est\nprécisément ce que l'interface\ncherche à masquer.\n"
        },
        {
          "text": "Sa couleur d'affichage dans l'éditeur",
          "correct": false,
          "feedback": "La couleur d'affichage relève\ndes préférences de l'éditeur,\net non de la définition d'une\ninterface en programmation.\n"
        }
      ],
      "explanation": "Une bonne pratique consiste à\n« programmer contre une interface,\npas contre une implémentation ».\nCela rend le code robuste face\naux changements internes des\nmodules dont il dépend."
    },
    {
      "id": "q16",
      "difficulty": 2,
      "skills": [
        "exemple-fonctionnel"
      ],
      "title": "Fonction d'ordre supérieur",
      "partie": "paradigmes",
      "statement": "Laquelle de ces écritures utilise explicitement\nune **fonction d'ordre supérieur**, trait\ncaractéristique du style fonctionnel ?",
      "options": [
        {
          "text": "```python\ncarres = list(map(lambda x: x * x, liste))\n```\n",
          "correct": true,
          "feedback": "`map` est une fonction d'ordre\nsupérieur : elle reçoit une\nfonction en argument (ici une\n`lambda` anonyme) et l'applique\nà chaque élément de la\ncollection. C'est le trait\nle plus caractéristique du\nstyle fonctionnel.\n"
        },
        {
          "text": "```python\ncarres = liste.map(square)\n```\n",
          "correct": false,
          "feedback": "Cette syntaxe n'est pas\nvalide en Python : les listes\nne possèdent pas de méthode\n`map`. La fonction `map` est\nune fonction native qui\ns'utilise différemment.\n"
        },
        {
          "text": "```python\ncarres = []\nfor x in liste:\n    carres.append(x * x)\n```\n",
          "correct": false,
          "feedback": "Cette écriture est typique du\nstyle impératif, avec une\nboucle et des modifications\nsuccessives d'une variable.\n"
        },
        {
          "text": "```python\ncarres = [x * x for x in liste]\n```\n",
          "correct": false,
          "feedback": "Cette compréhension de liste\nest d'esprit fonctionnel (pas\nde mutation explicite), mais\nelle n'appelle aucune fonction\nd'ordre supérieur : aucune\nfonction n'y est passée en\nargument à une autre fonction.\n"
        }
      ],
      "explanation": "Quelques outils fonctionnels en\nPython : `map`, `filter` et\n`lambda`. Ils sont idiomatiques\nmais doivent être utilisés avec\ndiscernement, sans sacrifier la\nlisibilité."
    },
    {
      "id": "q17",
      "difficulty": 2,
      "skills": [
        "reutilisation-bibli"
      ],
      "title": "Bibliothèques standard",
      "partie": "modularite",
      "statement": "Pourquoi est-il préférable de\nprivilégier les **bibliothèques standard** plutôt que de tout coder\nsoi-même ?",
      "options": [
        {
          "text": "Parce qu'aucun avantage réel ne distingue les deux approches",
          "correct": false,
          "feedback": "Les bibliothèques apportent au\ncontraire de nombreux\navantages : un code testé par\nde nombreux utilisateurs,\ndocumenté et maintenu.\n"
        },
        {
          "text": "Parce que Python impose d'utiliser ses bibliothèques standard",
          "correct": false,
          "feedback": "Aucune obligation n'est\nimposée : on peut tout\nréécrire soi-même. C'est une\nquestion de choix raisonné,\net non de contrainte.\n"
        },
        {
          "text": "Parce qu'elles rendent toujours le programme plus rapide",
          "correct": false,
          "feedback": "Une bibliothèque n'est pas\ntoujours plus rapide qu'un\ncode écrit à la main pour un\ncas précis. La performance\nn'est pas le critère\nprincipal pour préférer une\nbibliothèque, mais la qualité\net la fiabilité.\n"
        },
        {
          "text": "Parce que leur code est déjà testé, documenté et maintenu",
          "correct": true,
          "feedback": "Bonne réponse : ce code est de\nqualité, éprouvé par de très\nnombreux utilisateurs.\nLa probabilité de produire un\nmeilleur code seul, en\nquelques heures, qu'une\nbibliothèque standard\nmaintenue depuis des années\nest très faible. Sauf cas\nparticuliers (apprentissage,\ncontraintes spécifiques), la\nréutilisation est plus sage.\n"
        }
      ],
      "explanation": "Quelques bibliothèques standard utiles en Python : `math`, `random`, `csv`, `time`. Leur documentation décrit précisément chaque fonction, ce qui permet de s'en servir sans lire leur code."
    },
    {
      "id": "q18",
      "difficulty": 2,
      "skills": [
        "methode-self"
      ],
      "title": "Le paramètre self",
      "partie": "paradigmes",
      "statement": "Dans la définition d'une méthode\nPython, à quoi sert le premier\nparamètre, traditionnellement nommé\n`self` ?",
      "options": [
        {
          "text": "C'est un mot-clé réservé qu'il ne faut jamais modifier",
          "correct": false,
          "feedback": "Le nom `self` est une simple\nconvention, et non un mot-clé\nréservé du langage. On\npourrait techniquement\nl'appeler autrement, mais ce\nserait fortement déconseillé,\ncar cela briserait les\nhabitudes des autres\ndéveloppeurs.\n"
        },
        {
          "text": "Il représente la classe elle-même, pas l'instance",
          "correct": false,
          "feedback": "Le paramètre `self` représente précisément l'**instance** (l'objet créé), et non la classe dont elle est issue.\n"
        },
        {
          "text": "Il est rempli automatiquement avec la valeur $0$",
          "correct": false,
          "feedback": "Le paramètre `self` reçoit\nl'objet courant lors de\nl'appel, et non une valeur\nnumérique fixe.\n"
        },
        {
          "text": "Il désigne l'instance sur laquelle la méthode est appelée",
          "correct": true,
          "feedback": "Le paramètre `self` permet à\nla méthode d'accéder aux\nattributs et aux autres\nméthodes de l'objet courant,\npar exemple `self.marque`. Il\nfait le lien entre la méthode\nappelée et l'objet sur lequel\nelle s'exécute.\n"
        }
      ],
      "explanation": "Lors d'un appel comme\n`v.afficher()`, Python transmet\nautomatiquement l'objet `v`\ncomme premier paramètre `self`.\nLa méthode peut alors lire ou\nmodifier les attributs de `v`\nvia la notation\n`self.attribut`."
    },
    {
      "id": "q19",
      "difficulty": 2,
      "skills": [
        "vocabulaire-poo"
      ],
      "title": "Classe et instance",
      "partie": "paradigmes",
      "statement": "Quelle est la différence entre une\n**classe** et une **instance** ?",
      "options": [
        {
          "text": "Aucune différence",
          "correct": false,
          "feedback": "Les deux notions sont au\ncontraire bien distinctes,\ncomme expliqué dans la bonne\nréponse.\n"
        },
        {
          "text": "La notion d'instance est aujourd'hui obsolète",
          "correct": false,
          "feedback": "La notion d'instance reste\ncentrale en programmation\norientée objet : c'est l'objet\nconcret manipulé au cours de\nl'exécution.\n"
        },
        {
          "text": "La classe est le plan, l'instance un objet concret",
          "correct": true,
          "feedback": "Une analogie utile : la\nclasse est comme un moule à\ngâteaux, et les instances\nsont les gâteaux eux-mêmes.\nOn écrit `class Voiture:`\npour définir une classe et\n`ma_voiture = Voiture()` pour\nen créer une instance.\n"
        },
        {
          "text": "La classe s'exécute plus rapidement que l'instance",
          "correct": false,
          "feedback": "La rapidité d'exécution n'est\npas la différence pertinente\nentre classe et instance. Ce\nsont deux notions distinctes,\npas deux variantes d'un même\nconcept.\n"
        }
      ],
      "explanation": "Une classe peut avoir aucune,\nune, ou de très nombreuses\ninstances. Chaque instance\npossède son propre état (ses\npropres valeurs d'attributs),\nmais les méthodes restent\ndéfinies une seule fois, dans\nla classe."
    },
    {
      "id": "q20",
      "difficulty": 2,
      "skills": [
        "comparaison-paradigmes"
      ],
      "title": "Choisir un paradigme",
      "partie": "paradigmes",
      "statement": "Quel paradigme de programmation\nfaut-il privilégier ?",
      "options": [
        {
          "text": "Le paradigme objet, dans tous les cas",
          "correct": false,
          "feedback": "Cette position est trop\ndogmatique. Aucun paradigme\nn'est universellement\nsupérieur aux autres ; le\nchoix dépend du problème à\nrésoudre.\n"
        },
        {
          "text": "Le paradigme fonctionnel, dans tous les cas",
          "correct": false,
          "feedback": "Cette position est elle\naussi trop dogmatique. Le\nparadigme fonctionnel\nexcelle pour les\ntransformations de données,\nmais il n'est pas toujours\nle plus naturel pour tous\nles problèmes.\n"
        },
        {
          "text": "N'importe quel paradigme convient toujours",
          "correct": false,
          "feedback": "Il existe souvent un choix\nplus pertinent qu'un autre,\nen fonction de la nature du\nproblème à résoudre.\n"
        },
        {
          "text": "Cela dépend du problème à résoudre",
          "correct": true,
          "feedback": "Aucun paradigme n'est\nuniversellement meilleur. Un\nbon programmeur sait choisir\nl'outil adapté au contexte.\nBeaucoup de programmes\nmodernes mélangent\nd'ailleurs plusieurs\nparadigmes au sein d'un même\nprojet.\n"
        }
      ],
      "explanation": "La tendance moderne est aux\nlangages multi-paradigmes, qui\npermettent de mélanger les\nmeilleurs aspects de chaque\napproche selon le contexte."
    },
    {
      "id": "q22",
      "difficulty": 3,
      "skills": [
        "piege-poo"
      ],
      "title": "Piège classique de la programmation orientée objet",
      "partie": "paradigmes",
      "statement": "Quel est un **piège classique** de la\nprogrammation orientée objet ?",
      "options": [
        {
          "text": "Coder de manière trop simple",
          "correct": false,
          "feedback": "Le piège évoqué ici est\nprécisément l'inverse :\nc'est l'excès de complexité\nqui pose problème, pas la\nsimplicité.\n"
        },
        {
          "text": "La programmation orientée objet ne présente aucun piège",
          "correct": false,
          "feedback": "Comme tout paradigme, la\nprogrammation orientée objet\na ses pièges, dont l'excès\nde modélisation est l'un des\nplus classiques.\n"
        },
        {
          "text": "Modéliser en classes des cas qui ne le justifient pas",
          "correct": true,
          "feedback": "Pour calculer une simple\nsomme de notes, il n'est pas\nnécessaire de créer une\nclasse `CalculateurDeMoyenne`.\nUne fonction suffit\nlargement. La programmation\norientée objet a un coût en\ncomplexité qu'il faut savoir\npeser.\n"
        },
        {
          "text": "Utiliser des fonctions classiques",
          "correct": false,
          "feedback": "Utiliser des fonctions n'est\npas un piège ; c'est au\ncontraire souvent la bonne\nsolution face à des\nproblèmes simples.\n"
        }
      ],
      "explanation": "Une bonne maxime : choisir\nl'outil adapté au problème. Une\nclasse pour seulement deux\nfonctions s'apparente à un\nempilement inutile. À partir\nd'une méthode importante avec\nun état persistant, la classe\ndevient en revanche pertinente."
    },
    {
      "id": "q23",
      "difficulty": 3,
      "skills": [
        "definition-classe"
      ],
      "title": "Définir une classe",
      "partie": "paradigmes",
      "statement": "Quel squelette permet de définir une\nclasse `Point` avec deux attributs `x`\net `y` initialisés à la création ?",
      "options": [
        {
          "text": "```python\ndef Point(x, y):\n    self.x = x\n    self.y = y\n```\n",
          "correct": false,
          "feedback": "Cette définition utilise\n`def`, qui définit une\nfonction, et non une classe.\nIl manque le mot-clé\n`class`.\n"
        },
        {
          "text": "```python\nclass Point(x, y):\n    return x, y\n```\n",
          "correct": false,
          "feedback": "Les parenthèses qui suivent\nle nom d'une classe ne\nservent pas à déclarer ses\nattributs. Une définition\nde classe ne renvoie pas\nnon plus de valeur.\n"
        },
        {
          "text": "```python\nclass Point:\n    def __init__(x, y):\n        self.x = x\n        self.y = y\n```\n",
          "correct": false,
          "feedback": "Il manque le paramètre `self`\nen tête de `__init__`. À la\ncréation de l'objet, Python\ntransmet l'instance comme\npremier argument : l'appel\n`Point(3, 4)` fournit donc\ntrois arguments à une méthode\nqui n'en attend que deux, d'où\nune erreur `TypeError`.\n"
        },
        {
          "text": "```python\nclass Point:\n    def __init__(self, x, y):\n        self.x = x\n        self.y = y\n```\n",
          "correct": true,
          "feedback": "La méthode `__init__` est\nappelée automatiquement à la\ncréation de l'objet. Elle\nreçoit `self`, puis les\nvaleurs initiales, et les\nstocke en tant qu'attributs\nde l'instance.\n"
        }
      ],
      "explanation": "Le constructeur s'écrit\ntoujours sous la forme\n`def __init__(self, …):` et\nstocke les paramètres reçus\ndans `self`. Pour instancier la\nclasse, on écrit par exemple\n`p = Point(3, 4)` ; ensuite,\n`p.x` vaut $3$ et `p.y` vaut\n$4$."
    },
    {
      "id": "q25",
      "difficulty": 3,
      "skills": [
        "synthese"
      ],
      "title": "Synthèse",
      "partie": "paradigmes",
      "statement": "Parmi les affirmations suivantes\nsur la modularité et les\nparadigmes, laquelle est\n**fausse** ?",
      "options": [
        {
          "text": "Python est un langage purement fonctionnel",
          "correct": true,
          "feedback": "Cette affirmation est fausse\n(donc c'est la bonne\nréponse). Python est un\nlangage **multi-paradigmes**.\nIl prend en charge des\naspects fonctionnels\n(`lambda`, `map`,\ncompréhensions), mais il\nautorise aussi la mutation\ndes variables et les effets\nde bord, ce qui n'est pas\npossible dans un langage\npurement fonctionnel.\n"
        },
        {
          "text": "La modularité améliore la maintenabilité du code",
          "correct": false,
          "feedback": "Cette affirmation est\ncorrecte. La modularité est\nprécisément un facteur clé\nde maintenabilité.\n"
        },
        {
          "text": "Une fonction pure n'a pas d'effet de bord",
          "correct": false,
          "feedback": "Cette affirmation est\ncorrecte. L'absence d'effet\nde bord est précisément ce\nqui définit une fonction\npure.\n"
        },
        {
          "text": "Le paradigme objet structure le code autour d'objets combinant données et comportements",
          "correct": false,
          "feedback": "Cette affirmation est\ncorrecte. C'est même la\ndéfinition du paradigme\nobjet.\n"
        }
      ],
      "explanation": "Les langages purement\nfonctionnels les plus connus\nsont Haskell et Idris. Les\nlangages multi-paradigmes\nincluent Python, JavaScript,\nScala et OCaml."
    },
    {
      "id": "q26",
      "difficulty": 2,
      "skills": [
        "encapsulation"
      ],
      "title": "Encapsulation",
      "partie": "modularite",
      "statement": "Que désigne le principe\nd'**encapsulation** en programmation\norientée objet ?",
      "options": [
        {
          "text": "Réutiliser les classes\nd'un autre programme\n",
          "correct": false,
          "feedback": "Erreur : la réutilisation est\nun autre concept (lié à la\nmodularité). L'encapsulation\nconcerne le **masquage** des\ndétails internes derrière une\ninterface publique.\n"
        },
        {
          "text": "Mettre tout le code d'une\napplication dans un seul fichier\n",
          "correct": false,
          "feedback": "Erreur : c'est l'inverse de la\nmodularité. L'encapsulation va\nprécisément dans le sens\nopposé : on isole les\nresponsabilités dans des objets\n(ou modules) distincts.\n"
        },
        {
          "text": "Compresser un fichier avant de\nl'envoyer\n",
          "correct": false,
          "feedback": "Erreur : la compression de\ndonnées est sans rapport avec\nle concept d'encapsulation. Le\nterme « encapsulation » a un\nsens informatique précis,\ndifférent.\n"
        },
        {
          "text": "Regrouper données et méthodes, en masquant l'interne",
          "correct": true,
          "feedback": "Bonne réponse : c'est l'un des\npiliers de la programmation\norientée objet. L'utilisateur\nd'un objet manipule l'interface\npublique (les méthodes) sans\ndépendre du fonctionnement\ninterne (les attributs). On\npeut alors modifier\nl'implémentation sans casser\nle code utilisateur, tant que\nl'interface reste stable.\n"
        }
      ],
      "explanation": "L'encapsulation favorise le\ncouplage faible : un objet expose\nuniquement ce dont les autres ont\nbesoin (son interface publique) et\ncache le reste. C'est la base du\nprincipe « programmer contre une\ninterface, pas contre une\nimplémentation »."
    },
    {
      "id": "q27",
      "difficulty": 2,
      "skills": [
        "documentation",
        "bibliotheques"
      ],
      "title": "Lire la documentation de sorted",
      "partie": "modularite",
      "statement": "Un extrait simplifié de la documentation de Python indique : « `sorted(liste, reverse=False)` renvoie une **nouvelle** liste triée ; si `reverse` vaut `True`, le tri est décroissant ». Qu'affiche le programme suivant ?\n\n```python\nnotes = [12, 8, 15]\nt = sorted(notes, reverse=True)\nprint(notes, t)\n```",
      "options": [
        {
          "text": "`[15, 12, 8] [15, 12, 8]`",
          "correct": false,
          "feedback": "Erreur : la documentation précise que `sorted` renvoie une nouvelle liste. La liste `notes` n'est pas modifiée et s'affiche dans son ordre d'origine.\n"
        },
        {
          "text": "`[12, 8, 15] [8, 12, 15]`",
          "correct": false,
          "feedback": "Erreur : le paramètre `reverse=True` demande un tri décroissant. Sans lui, on obtiendrait bien `[8, 12, 15]`.\n"
        },
        {
          "text": "`[12, 8, 15] [15, 12, 8]`",
          "correct": true,
          "feedback": "Bonne réponse : `sorted` construit une nouvelle liste, triée par ordre décroissant grâce à `reverse=True`, et laisse `notes` intacte.\n"
        },
        {
          "text": "`[8, 12, 15] [15, 12, 8]`",
          "correct": false,
          "feedback": "Erreur : `sorted` ne trie pas `notes` sur place, il fabrique une autre liste. La liste `notes` s'affiche telle qu'elle a été créée.\n"
        }
      ],
      "explanation": "Exploiter la documentation d'une fonction permet de savoir, sans lire son code, ce qu'elle renvoie, si elle modifie ses arguments et à quoi servent ses paramètres optionnels, comme `reverse`."
    },
    {
      "id": "q24",
      "difficulty": 3,
      "skills": [
        "synthese",
        "paradigme",
        "identification"
      ],
      "title": "Reconnaître un paradigme",
      "partie": "paradigmes",
      "statement": "Considérez le fragment Python suivant :\n\n`print(sum(map(lambda x: x ** 2, range(10))))`\n\nQuel **paradigme** de programmation ce style illustre-t-il\nprincipalement ?",
      "options": [
        {
          "text": "La programmation fonctionnelle (`map`, `lambda`)",
          "correct": true,
          "feedback": "Bonne réponse : la programmation fonctionnelle se\nreconnaît à la composition de fonctions, à\nl'absence de variables intermédiaires modifiées\nen place, et à l'utilisation de fonctions comme\nparamètres (ici, la `lambda` passée à `map`).\nPython supporte ce style tout en restant\nprincipalement impératif.\n"
        },
        {
          "text": "La programmation orientée objet, car on utilise des méthodes implicites",
          "correct": false,
          "feedback": "Erreur : aucune classe ni méthode n'est définie\nexplicitement ici. Le code ne s'articule pas autour\nd'objets et de messages, mais autour de la\ncomposition de fonctions.\n"
        },
        {
          "text": "La programmation impérative, car on imprime un résultat à l'écran",
          "correct": false,
          "feedback": "Erreur : la présence de `print` ne suffit pas à\ncaractériser le style. Le cœur du calcul est\nfonctionnel ; `print` est juste l'instruction\nd'affichage finale.\n"
        },
        {
          "text": "La programmation logique, car le code déclare un ensemble de contraintes",
          "correct": false,
          "feedback": "Erreur : la programmation logique (Prolog par\nexemple) repose sur des règles et des prédicats,\npas sur des compositions de fonctions. Le fragment\nprésenté ici n'est pas déclaratif au sens logique.\n"
        }
      ],
      "explanation": "Un même langage peut accueillir plusieurs paradigmes.\nPython est multiparadigme : on peut écrire ce calcul\nde manière impérative\n(`total = 0; for x in range(10): total += x ** 2`),\norientée objet (en passant par une classe), ou\nfonctionnelle (comme ici). Choisir le style adapté à\nchaque problème fait partie de la culture du\nprogrammeur."
    },
    {
      "id": "q28",
      "difficulty": 3,
      "skills": [
        "paradigmes",
        "synthese"
      ],
      "title": "Paradigmes mêlés dans un programme de notes",
      "partie": "paradigmes",
      "statement": "On considère le programme suivant :\n\n```python\nclass Eleve:\n    def __init__(self, nom, notes):\n        self.nom = nom\n        self.notes = notes\n\ndef moyenne(e):\n    return sum(e.notes) / len(e.notes)\n\nclasse = [Eleve(\"Léa\", [12, 16]), Eleve(\"Tom\", [9, 10])]\nadmis = list(filter(lambda e: moyenne(e) >= 10, classe))\nnoms = []\nfor e in admis:\n    noms.append(e.nom)\n```\n\nQuels paradigmes de programmation ce programme mobilise-t-il ?",
      "options": [
        {
          "text": "Uniquement objet, puisqu'il définit une classe",
          "correct": false,
          "feedback": "Erreur : la classe `Eleve` relève bien du paradigme objet, mais le programme ne s'y limite pas. Le filtrage par `filter` et `lambda` est fonctionnel, la boucle qui remplit `noms` est impérative.\n"
        },
        {
          "text": "Objet, fonctionnel et impératif",
          "correct": true,
          "feedback": "Bonne réponse : la classe `Eleve` et ses attributs relèvent de l'objet, `filter` avec une `lambda` du fonctionnel, et la boucle qui ajoute les noms un à un en modifiant la liste `noms` de l'impératif.\n"
        },
        {
          "text": "Objet et impératif, `filter` n'étant qu'une boucle",
          "correct": false,
          "feedback": "Erreur : `filter` applique une fonction passée en argument, ici une `lambda`, sans modifier de variable : c'est une construction typique du paradigme fonctionnel, même si elle parcourt la liste.\n"
        },
        {
          "text": "Uniquement fonctionnel, car tout passe par des fonctions",
          "correct": false,
          "feedback": "Erreur : définir des fonctions ne suffit pas à rendre un programme fonctionnel. La classe `Eleve` relève de l'objet, et la boucle `for` qui modifie `noms` au fil des tours est impérative.\n"
        }
      ],
      "explanation": "Avec un même langage, et même dans un même programme, on peut mêler plusieurs paradigmes. On choisit pour chaque partie le style le plus adapté : objets pour modéliser les élèves, fonctions pour filtrer, boucle pour accumuler un résultat."
    },
    {
      "id": "q29",
      "difficulty": 1,
      "skills": [
        "api",
        "definition",
        "bibliotheques"
      ],
      "title": "Ce qu'est une API",
      "partie": "modularite",
      "statement": "Qu'appelle-t-on l'**API** (interface de\nprogrammation) d'une bibliothèque ou d'un service ?",
      "options": [
        {
          "text": "Les fonctions, classes et constantes qu'elle offre aux programmes, avec leur mode d'emploi",
          "correct": true,
          "feedback": "C'est le contrat entre la bibliothèque et ceux\nqui l'utilisent ; le fonctionnement interne reste\ncaché.\n"
        },
        {
          "text": "Le code source complet de la bibliothèque, qu'il faut lire en entier avant de pouvoir l'utiliser",
          "correct": false,
          "feedback": "Utiliser une bibliothèque ne demande pas d'en\nlire le code : la documentation de l'interface\nsuffit.\n"
        },
        {
          "text": "L'interface graphique (fenêtres, boutons, menus) par laquelle un utilisateur manipule l'application",
          "correct": false,
          "feedback": "Une API s'adresse aux programmes, pas aux\nutilisateurs ; les deux notions sont distinctes.\n"
        },
        {
          "text": "Un langage de programmation particulier, réservé à l'écriture des applications destinées au web",
          "correct": false,
          "feedback": "Une API n'est pas un langage ; on l'appelle\ndepuis Python, JavaScript ou tout autre langage.\n"
        }
      ],
      "explanation": "Une API décrit ce qu'on peut demander à un module ou\nà un service en ligne et sous quelle forme : noms\ndes fonctions, paramètres, valeurs renvoyées. Elle\nsépare l'usage de l'implémentation, ce qui permet de\nfaire évoluer l'un sans toucher à l'autre."
    },
    {
      "id": "q30",
      "difficulty": 2,
      "skills": [
        "api",
        "documentation",
        "utilisation"
      ],
      "title": "Utiliser une fonction d'après sa documentation",
      "partie": "modularite",
      "statement": "La documentation du module `meteo` indique :\n« `temperature(ville)` renvoie la température\nactuelle de la ville, en degrés Celsius, sous forme\nde flottant ; renvoie `None` si la ville est\ninconnue. » Quel programme utilise correctement\ncette fonction ?",
      "options": [
        {
          "text": "```python\nimport meteo\nt = meteo.temperature(\"Lyon\")\nif t is None:\n    print(\"ville inconnue\")\nelse:\n    print(t)\n```\n",
          "correct": true,
          "feedback": "Appel par le nom du module, un seul argument, et\nprise en compte du cas `None` prévu par la\ndocumentation.\n"
        },
        {
          "text": "```python\nimport meteo\nt = meteo.temperature(\"Lyon\", \"Celsius\")\nprint(t)\n```\n",
          "correct": false,
          "feedback": "La documentation annonce un seul paramètre ;\nl'unité est fixée par la fonction. Un second\nargument provoque une `TypeError`.\n"
        },
        {
          "text": "```python\nimport meteo\nprint(temperature(\"Lyon\"))\n```\n",
          "correct": false,
          "feedback": "Après `import meteo`, la fonction s'appelle\n`meteo.temperature` ; sans ce préfixe,\n`temperature` est un nom inconnu (`NameError`).\n"
        },
        {
          "text": "```python\nimport meteo\nif meteo.temperature == \"Lyon\":\n    print(meteo.temperature)\n```\n",
          "correct": false,
          "feedback": "Ce code compare la fonction elle-même à une\nchaîne, sans jamais l'appeler ; il n'affiche\njamais rien.\n"
        }
      ],
      "explanation": "Utiliser une API, c'est respecter son contrat : nom,\nparamètres, type du résultat et cas particuliers\nannoncés. La documentation dit tout ce qu'il faut\nsavoir, sans lire le code du module."
    },
    {
      "id": "q31",
      "difficulty": 2,
      "skills": [
        "modularite",
        "import",
        "espace-de-noms"
      ],
      "title": "Importer tous les noms d'un module",
      "partie": "modularite",
      "statement": "Pourquoi déconseille-t-on l'écriture `from outils import *` ?",
      "options": [
        {
          "text": "Elle importe tous les noms, au risque d'en écraser d'autres",
          "correct": true,
          "feedback": "Bonne réponse : une fonction `moyenne` du programme peut être\nremplacée en silence par celle du module, et l'origine de\nchaque nom devient impossible à lire.\n"
        },
        {
          "text": "Elle n'importe que les fonctions, jamais les constantes",
          "correct": false,
          "feedback": "Erreur : elle importe tous les noms publics, constantes\ncomprises.\n"
        },
        {
          "text": "Elle recopie le fichier du module à l'intérieur du programme",
          "correct": false,
          "feedback": "Erreur : le module est chargé une fois, rien n'est recopié.\n"
        },
        {
          "text": "Elle n'est permise que pour les modules de la bibliothèque standard",
          "correct": false,
          "feedback": "Erreur : elle fonctionne avec tout module, c'est bien le\nproblème.\n"
        }
      ],
      "explanation": "`import outils` puis `outils.moyenne(...)` garde chaque nom dans\nson espace : on sait d'où vient chaque fonction."
    },
    {
      "id": "q32",
      "difficulty": 1,
      "skills": [
        "modularite",
        "import",
        "alias"
      ],
      "title": "Importer un module sous un alias",
      "partie": "modularite",
      "statement": "Après `import random as rd`, comment appeler la fonction `randint`\nde ce module ?",
      "options": [
        {
          "text": "`rd.randint(1, 6)`, `rd` désignant le module `random`",
          "correct": true,
          "feedback": "Bonne réponse : l'alias remplace le nom du module dans tout le\nprogramme.\n"
        },
        {
          "text": "`random.randint(1, 6)`, l'alias n'étant qu'un commentaire",
          "correct": false,
          "feedback": "Erreur : avec un alias, le nom `random` n'est pas défini dans le\nprogramme.\n"
        },
        {
          "text": "`randint(1, 6)`, toutes les fonctions étant importées",
          "correct": false,
          "feedback": "Erreur : `import` ne place pas les fonctions dans l'espace du\nprogramme, il faut préfixer.\n"
        },
        {
          "text": "`rd(randint, 1, 6)`, l'alias étant une fonction d'appel",
          "correct": false,
          "feedback": "Erreur : `rd` est le module, pas une fonction.\n"
        }
      ],
      "explanation": "Un alias raccourcit le nom d'un module sans renoncer au préfixe,\nqui dit d'où vient chaque fonction."
    },
    {
      "id": "q33",
      "difficulty": 1,
      "skills": [
        "modularite",
        "module",
        "fichier"
      ],
      "title": "Ce que cherche une instruction d'importation",
      "partie": "modularite",
      "statement": "Que cherche Python quand il exécute `import outils` ?",
      "options": [
        {
          "text": "Un fichier `outils.py` sur le chemin de recherche des modules",
          "correct": true,
          "feedback": "Bonne réponse : un module est un fichier Python ; Python\nl'exécute une fois et rend ses définitions accessibles sous le\nnom `outils`.\n"
        },
        {
          "text": "Une fonction nommée `outils` définie plus haut dans le programme",
          "correct": false,
          "feedback": "Erreur : `import` ne concerne pas les fonctions du programme\ncourant.\n"
        },
        {
          "text": "Un dossier `outils` contenant obligatoirement un fichier `main.py`",
          "correct": false,
          "feedback": "Erreur : un simple fichier suffit ; les dossiers ont leurs\npropres règles.\n"
        },
        {
          "text": "Une variable `outils` contenant le texte du module sous forme de chaîne",
          "correct": false,
          "feedback": "Erreur : le module n'est pas du texte stocké dans une variable,\nc'est un fichier chargé.\n"
        }
      ],
      "explanation": "Écrire un module, c'est écrire un fichier `.py` ; l'importer,\nc'est le charger sous son nom."
    },
    {
      "id": "q34",
      "difficulty": 3,
      "skills": [
        "modularite",
        "dependance",
        "interface",
        "implementation"
      ],
      "title": "Une modification dans un module importé",
      "partie": "modularite",
      "statement": "Le module `A` importe et utilise le module `B`. On modifie `B`.\nDans quel cas `A` risque-t-il de ne plus fonctionner ?",
      "options": [
        {
          "text": "Si l'interface de `B` change, noms ou paramètres de fonctions",
          "correct": true,
          "feedback": "Bonne réponse : `A` ne connaît de `B` que son interface. Tant\nque les fonctions gardent leur nom, leurs paramètres et leur\ncomportement annoncé, leur réécriture interne est invisible.\n"
        },
        {
          "text": "Toujours, la moindre modification de `B` se répercutant sur `A`",
          "correct": false,
          "feedback": "Erreur : changer l'implémentation d'une fonction sans changer\nson interface ne touche pas `A`.\n"
        },
        {
          "text": "Jamais, les deux modules étant des fichiers indépendants",
          "correct": false,
          "feedback": "Erreur : `A` dépend de `B`, puisqu'il l'importe.\n"
        },
        {
          "text": "Seulement si `A` et `B` sont écrits dans le même fichier source",
          "correct": false,
          "feedback": "Erreur : ce sont deux fichiers, et la dépendance passe par\nl'importation.\n"
        }
      ],
      "explanation": "Séparer interface et implémentation permet de faire évoluer un\nmodule sans toucher à ceux qui l'utilisent."
    },
    {
      "id": "q35",
      "difficulty": 2,
      "skills": [
        "paradigmes",
        "declaratif",
        "sql"
      ],
      "title": "Le paradigme d'une requête SQL",
      "partie": "paradigmes",
      "statement": "Une requête `SELECT nom FROM eleves WHERE note > 15` décrit le\nrésultat voulu sans indiquer comment le calculer. De quel\nparadigme relève-t-elle ?",
      "options": [
        {
          "text": "Déclaratif, on décrit le résultat sans dire comment l'obtenir",
          "correct": true,
          "feedback": "Bonne réponse : le système de gestion de bases de données\nchoisit lui-même l'ordre des opérations et les index à\nutiliser.\n"
        },
        {
          "text": "Impératif, la requête étant une suite d'instructions",
          "correct": false,
          "feedback": "Erreur : aucune boucle ni affectation, aucun ordre\nd'exécution imposé.\n"
        },
        {
          "text": "Objet, chaque table étant un objet avec ses méthodes",
          "correct": false,
          "feedback": "Erreur : la requête ne manipule ni classe ni méthode.\n"
        },
        {
          "text": "Fonctionnel, la requête étant une fonction pure",
          "correct": false,
          "feedback": "Erreur : le style fonctionnel compose des fonctions ; SQL\ndécrit un résultat.\n"
        }
      ],
      "explanation": "Impératif, objet et fonctionnel disent comment calculer ; le\ndéclaratif dit seulement quoi obtenir."
    },
    {
      "id": "q36",
      "difficulty": 2,
      "skills": [
        "paradigmes",
        "evenementiel",
        "interface"
      ],
      "title": "Un programme qui réagit aux clics",
      "partie": "paradigmes",
      "statement": "Dans une page web, une fonction est associée à un bouton et ne\ns'exécute qu'au clic ; le programme attend sinon sans rien faire.\nComment appelle-t-on ce style ?",
      "options": [
        {
          "text": "Événementiel, le code répondant aux actions de l'utilisateur",
          "correct": true,
          "feedback": "Bonne réponse : le programme ne déroule pas une suite\nd'instructions, il enregistre des réactions et attend les\névénements.\n"
        },
        {
          "text": "Impératif pur, les instructions se suivant dans l'ordre du fichier",
          "correct": false,
          "feedback": "Erreur : l'ordre d'exécution dépend des clics, pas du fichier.\n"
        },
        {
          "text": "Fonctionnel, le bouton se contentant d'appeler une fonction",
          "correct": false,
          "feedback": "Erreur : appeler une fonction ne suffit pas ; c'est l'attente\nd'événements qui caractérise ce style.\n"
        },
        {
          "text": "Récursif, chaque clic rappelant le programme depuis le début",
          "correct": false,
          "feedback": "Erreur : aucun appel récursif n'intervient.\n"
        }
      ],
      "explanation": "Les interfaces graphiques et le web reposent sur la programmation\névénementielle, souvent mêlée aux autres paradigmes."
    },
    {
      "id": "q37",
      "difficulty": 3,
      "skills": [
        "paradigmes",
        "objet",
        "fonctionnel",
        "methode-pure"
      ],
      "title": "Une méthode qui ne modifie rien",
      "partie": "paradigmes",
      "statement": "Cette méthode est-elle compatible avec le style fonctionnel ?\n```python\nclass Point:\n    def __init__(self, x, y):\n        self.x = x\n        self.y = y\n\n    def distance(self, autre):\n        return ((self.x - autre.x) ** 2 + (self.y - autre.y) ** 2) ** 0.5\n```",
      "options": [
        {
          "text": "Oui, sans modification ni effet de bord, comme une fonction pure",
          "correct": true,
          "feedback": "Bonne réponse : `distance` lit les attributs sans les changer et\nson résultat ne dépend que des deux points. Les paradigmes se\ncombinent : des objets immuables et des méthodes pures.\n"
        },
        {
          "text": "Non, toute méthode modifie l'objet sur lequel elle est appelée",
          "correct": false,
          "feedback": "Erreur : une méthode peut se contenter de lire les attributs.\n"
        },
        {
          "text": "Non, les classes et leurs méthodes relèvent du seul paradigme objet",
          "correct": false,
          "feedback": "Erreur : un programme mêle couramment objets et fonctions\npures.\n"
        },
        {
          "text": "Oui, mais seulement si la classe ne possède aucun attribut modifiable",
          "correct": false,
          "feedback": "Erreur : lire des attributs ne crée aucun effet de bord.\n"
        }
      ],
      "explanation": "Ce qui compte pour la pureté, c'est l'absence de modification et\nde dépendance à un état caché, pas la syntaxe employée."
    }
  ]
}