{
  "chapter": {
    "id": "variables-types-de-base",
    "level": "premiere",
    "theme": "Programmation",
    "title": "Variables et types de base",
    "description": "Variables Python, affectation, types primitifs (entier,\nflottant, chaîne, booléen), conversions de types,\nopérateurs arithmétiques et logiques, opérations de base\nsur les chaînes.",
    "prerequisites": [],
    "references": []
  },
  "questions": [
    {
      "id": "q01",
      "difficulty": 1,
      "skills": [
        "affectation"
      ],
      "title": "Affectation",
      "statement": "Quelle est la signification de l'instruction\n`x = 5` en Python ?",
      "options": [
        {
          "text": "Affecter la valeur 5 à la variable `x`",
          "correct": true,
          "feedback": "Bonne réponse : on fait pointer le nom `x`\nvers la valeur `5`. Si `x` n'existait pas,\nla variable est créée ; sinon, elle est mise\nà jour.\n"
        },
        {
          "text": "Tester si `x` est égal à 5",
          "correct": false,
          "feedback": "Erreur : le test d'égalité s'écrit `==` (deux\nsignes égal). Avec un seul `=`, c'est une\n**affectation**.\n"
        },
        {
          "text": "Définir une fonction `x` qui renvoie 5",
          "correct": false,
          "feedback": "Erreur : une fonction se définit avec `def`.\n"
        },
        {
          "text": "Multiplier `x` par 5",
          "correct": false,
          "feedback": "Erreur : la multiplication s'écrit `x * 5`.\n"
        }
      ],
      "explanation": "L'opérateur `=` est l'**affectation** (asymétrique :\ngauche reçoit droite). À ne pas confondre avec\n`==` qui est le **test d'égalité** (symétrique,\nbooléen)."
    },
    {
      "id": "q02",
      "difficulty": 1,
      "skills": [
        "type-int"
      ],
      "title": "Type entier",
      "statement": "Quel est le type de la valeur `42` en Python ?",
      "options": [
        {
          "text": "`int`",
          "correct": true,
          "feedback": "Bonne réponse : `42` est un **entier** (type\n`int`). On peut le vérifier avec\n`type(42)` qui renvoie `<class 'int'>`.\n"
        },
        {
          "text": "`str`",
          "correct": false,
          "feedback": "Erreur : `42` n'a pas de guillemets, ce n'est\npas une chaîne.\n"
        },
        {
          "text": "`bool`",
          "correct": false,
          "feedback": "Erreur : les booléens sont `True` et `False`.\n"
        },
        {
          "text": "`float`",
          "correct": false,
          "feedback": "Erreur : `42.0` serait un flottant. Sans\nvirgule, c'est un entier.\n"
        }
      ],
      "explanation": "Python distingue `int` (entiers, précision\narbitraire) et `float` (flottants, précision\nfinie). `42` et `42.0` sont distincts (mais\négaux par valeur)."
    },
    {
      "id": "q03",
      "difficulty": 1,
      "skills": [
        "type-float"
      ],
      "title": "Type flottant",
      "statement": "Que renvoie `type(3.14)` en Python ?",
      "options": [
        {
          "text": "`<class 'int'>`",
          "correct": false,
          "feedback": "Erreur : `3.14` a une partie décimale, c'est\nun flottant.\n"
        },
        {
          "text": "`<class 'decimal'>`",
          "correct": false,
          "feedback": "Erreur : `decimal` est un module spécialisé,\nmais le type natif des nombres à virgule est\n`float`.\n"
        },
        {
          "text": "`<class 'float'>`",
          "correct": true,
          "feedback": "Bonne réponse : tout nombre avec un point\ndécimal est un flottant en Python.\n"
        },
        {
          "text": "`<class 'str'>`",
          "correct": false,
          "feedback": "Erreur : pas de guillemets.\n"
        }
      ],
      "explanation": "Attention : les flottants ont une **précision\nlimitée**. `0.1 + 0.2` ne donne pas exactement\n`0.3` mais `0.30000000000000004` à cause de la\nreprésentation binaire IEEE 754."
    },
    {
      "id": "q04",
      "difficulty": 1,
      "skills": [
        "type-str"
      ],
      "title": "Type chaîne",
      "statement": "Quel est le type de `\"hello\"` en Python ?",
      "options": [
        {
          "text": "`str`",
          "correct": true,
          "feedback": "Bonne réponse : les chaînes de caractères\nsont du type `str` (string). On les écrit\nentre guillemets simples (`'`) ou doubles\n(`\"`).\n"
        },
        {
          "text": "`int`",
          "correct": false,
          "feedback": "Erreur : `\"hello\"` est entre guillemets,\nc'est une chaîne.\n"
        },
        {
          "text": "`bool`",
          "correct": false,
          "feedback": "Erreur : un booléen est `True` ou `False`.\n"
        },
        {
          "text": "`char`",
          "correct": false,
          "feedback": "Erreur : pas de type `char` en Python (à la\ndifférence de C ou Java). Un caractère est\njuste une chaîne de longueur 1.\n"
        }
      ],
      "explanation": "Python n'a pas de type spécifique pour un seul\ncaractère : `'a'` est une chaîne de longueur 1."
    },
    {
      "id": "q05",
      "difficulty": 1,
      "skills": [
        "type-bool"
      ],
      "title": "Type booléen",
      "statement": "Quelles sont les **deux seules** valeurs du type\n`bool` en Python ?",
      "options": [
        {
          "text": "`True` et `False`",
          "correct": true,
          "feedback": "Bonne réponse : avec une **majuscule\nobligatoire**. `true` ou `false` (en\nminuscules) provoqueraient une erreur.\n"
        },
        {
          "text": "`oui` et `non`",
          "correct": false,
          "feedback": "Erreur : Python est en anglais, pas en\nfrançais.\n"
        },
        {
          "text": "`yes` et `no`",
          "correct": false,
          "feedback": "Erreur : ces mots-clés n'existent pas en\nPython.\n"
        },
        {
          "text": "`0` et `1`",
          "correct": false,
          "feedback": "Erreur : ce sont des entiers. Ils sont\ninterprétés comme booléens (0 = faux, 1 =\nvrai) mais leur type reste `int`.\n"
        }
      ],
      "explanation": "Mnémonique : majuscule à `True` et `False`,\npas comme en JavaScript ou C."
    },
    {
      "id": "q06",
      "difficulty": 1,
      "skills": [
        "conversion"
      ],
      "title": "Conversion en entier",
      "statement": "Que renvoie `int(\"42\")` ?",
      "options": [
        {
          "text": "La chaîne `\"42\"`",
          "correct": false,
          "feedback": "Erreur : `int(...)` renvoie un entier, pas\nune chaîne.\n"
        },
        {
          "text": "L'entier `42`",
          "correct": true,
          "feedback": "Bonne réponse : `int(s)` convertit la chaîne\n`s` en son entier correspondant. Utile pour\nlire une saisie utilisateur (`input()`\nrenvoie toujours une chaîne).\n"
        },
        {
          "text": "Une erreur",
          "correct": false,
          "feedback": "Erreur : `\"42\"` est convertible. Une chaîne\ncomme `\"abc\"` lèverait `ValueError`.\n"
        },
        {
          "text": "Le flottant `42.0`",
          "correct": false,
          "feedback": "Erreur : `int` produit un entier, pas un\nflottant. Utiliser `float(\"42\")` pour cela.\n"
        }
      ],
      "explanation": "`int(x)` accepte : entiers (renvoie x), flottants\n(tronque vers 0), chaînes représentant un entier.\nAvec `int(\"3.14\")`, ça lève `ValueError`."
    },
    {
      "id": "q07",
      "difficulty": 1,
      "skills": [
        "operateurs-arithmetique"
      ],
      "title": "Opérateur de division",
      "statement": "Que renvoie `7 / 2` en Python 3 ?",
      "options": [
        {
          "text": "3",
          "correct": false,
          "feedback": "Erreur : c'est la division entière (`//`).\n"
        },
        {
          "text": "Une erreur",
          "correct": false,
          "feedback": "Erreur : la syntaxe est valide.\n"
        },
        {
          "text": "4",
          "correct": false,
          "feedback": "Erreur : pas d'arrondi.\n"
        },
        {
          "text": "3.5",
          "correct": true,
          "feedback": "Bonne réponse : en Python 3, `/` est la\ndivision **flottante**. Toujours, même entre\ndeux entiers.\n"
        }
      ],
      "explanation": "Distinction Python 3 : `/` = division flottante\n(toujours `float`) ; `//` = division entière\n(entier si les deux opérandes sont entiers)."
    },
    {
      "id": "q08",
      "difficulty": 1,
      "skills": [
        "division-entiere"
      ],
      "title": "Division entière",
      "statement": "Que renvoie `7 // 2` ?",
      "options": [
        {
          "text": "0",
          "correct": false,
          "feedback": "Erreur : 0 est le reste, pas le quotient.\n"
        },
        {
          "text": "4",
          "correct": false,
          "feedback": "Erreur : pas d'arrondi à l'entier supérieur,\nmais troncature vers le bas.\n"
        },
        {
          "text": "3.5",
          "correct": false,
          "feedback": "Erreur : c'est la division **flottante**\n(`/`).\n"
        },
        {
          "text": "3",
          "correct": true,
          "feedback": "Bonne réponse : `//` est la division\n**entière** (quotient sans le reste).\n"
        }
      ],
      "explanation": "Avec des **négatifs**, attention : `-7 // 2`\nvaut `-4` (arrondi vers le bas, pas vers 0).\nCohérent avec `a == (a // b) * b + a % b`."
    },
    {
      "id": "q09",
      "difficulty": 1,
      "skills": [
        "modulo"
      ],
      "title": "Modulo",
      "statement": "Que renvoie `7 % 2` ?",
      "options": [
        {
          "text": "1",
          "correct": true,
          "feedback": "Bonne réponse : `%` calcule le **reste**\nde la division entière. 7 = 3 × 2 + 1, donc\n7 % 2 = 1.\n"
        },
        {
          "text": "3.5",
          "correct": false,
          "feedback": "Erreur : c'est `/`, pas `%`.\n"
        },
        {
          "text": "0",
          "correct": false,
          "feedback": "Erreur : 7 est impair, son reste modulo 2\nest 1.\n"
        },
        {
          "text": "3",
          "correct": false,
          "feedback": "Erreur : 3 est le quotient (`//`), pas le\nreste.\n"
        }
      ],
      "explanation": "Très utile : `n % 2` permet de tester la parité\n(`n % 2 == 0` ⇔ pair). De manière plus\ngénérale, `n % k` regarde la classe modulo k."
    },
    {
      "id": "q10",
      "difficulty": 1,
      "skills": [
        "print"
      ],
      "title": "Print",
      "statement": "Que fait l'instruction `print(\"bonjour\")` ?",
      "options": [
        {
          "text": "Définit une variable nommée `bonjour`",
          "correct": false,
          "feedback": "Erreur : `print` affiche, ne définit pas.\n"
        },
        {
          "text": "Ne fait rien",
          "correct": false,
          "feedback": "Erreur : `print` produit un effet visible.\n"
        },
        {
          "text": "Affiche `bonjour` dans la console",
          "correct": true,
          "feedback": "Bonne réponse : c'est l'affichage standard.\nPour ajouter à la fin, utiliser\n`print(x, end=\"\")` ; pour séparer plusieurs\narguments, `print(a, b, sep=\", \")`.\n"
        },
        {
          "text": "Imprime sur l'imprimante de l'ordinateur",
          "correct": false,
          "feedback": "Confusion : `print` affiche dans la\n**console** (sortie standard), pas sur une\nimprimante physique.\n"
        }
      ],
      "explanation": "`print` est utile pour le **débogage** rapide.\nPour des programmes plus structurés, on\nprivilégie le module `logging`."
    },
    {
      "id": "q11",
      "difficulty": 2,
      "skills": [
        "type-dynamique"
      ],
      "title": "Typage dynamique",
      "statement": "```python\nx = 5\nx = \"hello\"\n```\nCette suite d'instructions est-elle valide ?",
      "options": [
        {
          "text": "Non, il faut redéclarer `x`",
          "correct": false,
          "feedback": "Erreur : aucune « redéclaration » nécessaire\nen Python.\n"
        },
        {
          "text": "Oui, mais Python affiche un avertissement",
          "correct": false,
          "feedback": "Erreur : aucun avertissement par défaut.\n"
        },
        {
          "text": "Non, `x` est figé en entier",
          "correct": false,
          "feedback": "Erreur : ce serait le cas dans un langage à\n**typage statique** (Java, C++, Rust),\nmais pas en Python.\n"
        },
        {
          "text": "Oui, parce que Python est typé dynamiquement : une variable peut changer de type au cours du programme",
          "correct": true,
          "feedback": "Bonne réponse : Python autorise cette\nréaffectation. Attention : c'est puissant\nmais peut causer des bugs subtils.\n"
        }
      ],
      "explanation": "Avec le typage dynamique, on gagne en\nflexibilité mais on perd en sécurité. Les\nannotations de type (`x: int = 5`) et `mypy`\npermettent une vérification statique\noptionnelle."
    },
    {
      "id": "q12",
      "difficulty": 2,
      "skills": [
        "conversion-erreur"
      ],
      "title": "Conversion qui plante",
      "statement": "Que se passe-t-il avec `int(\"abc\")` ?",
      "options": [
        {
          "text": "Renvoie `0`",
          "correct": false,
          "feedback": "Erreur : Python ne renvoie pas une valeur\npar défaut, il lève une exception.\n"
        },
        {
          "text": "Renvoie `None`",
          "correct": false,
          "feedback": "Erreur : pas de retour silencieux à `None`.\n"
        },
        {
          "text": "Renvoie `\"abc\"`",
          "correct": false,
          "feedback": "Erreur : `int(...)` est censé renvoyer un\nentier, pas une chaîne.\n"
        },
        {
          "text": "Lève `ValueError`",
          "correct": true,
          "feedback": "Bonne réponse : Python lève `ValueError:\ninvalid literal for int() with base 10:\n'abc'`. À gérer avec un `try/except`.\n"
        }
      ],
      "explanation": "Bonne pratique : protéger les conversions de\nsaisies utilisateur avec un `try/except`.\n```python\ntry:\n    n = int(input())\nexcept ValueError:\n    print(\"Pas un entier\")\n```"
    },
    {
      "id": "q13",
      "difficulty": 2,
      "skills": [
        "concatenation"
      ],
      "title": "Concaténation",
      "statement": "Que renvoie `\"abc\" + \"def\"` ?",
      "options": [
        {
          "text": "`abc def`",
          "correct": false,
          "feedback": "Erreur : aucun espace n'est ajouté\nautomatiquement par `+`.\n"
        },
        {
          "text": "`9` (somme alphabétique)",
          "correct": false,
          "feedback": "Erreur : aucune somme alphabétique.\n"
        },
        {
          "text": "Une erreur",
          "correct": false,
          "feedback": "Erreur : la syntaxe est valide.\n"
        },
        {
          "text": "`abcdef`",
          "correct": true,
          "feedback": "Bonne réponse : `+` concatène deux chaînes.\nLe résultat est `\"abcdef\"` (sans espace,\nsauf indication explicite).\n"
        }
      ],
      "explanation": "`+` est **surchargé** : addition pour les\nnombres, concaténation pour les chaînes et\nles listes. Mais pas de mélange : `\"a\" + 5`\nlève `TypeError`."
    },
    {
      "id": "q14",
      "difficulty": 2,
      "skills": [
        "repetition"
      ],
      "title": "Répétition de chaîne",
      "statement": "Que renvoie `\"ab\" * 3` ?",
      "options": [
        {
          "text": "`ababab`",
          "correct": true,
          "feedback": "Bonne réponse : `*` répète une chaîne. C'est\nun raccourci très pratique :\n`\"-\" * 80` produit une ligne de tirets.\n"
        },
        {
          "text": "Une erreur",
          "correct": false,
          "feedback": "Erreur : la syntaxe est valide.\n"
        },
        {
          "text": "`6` (longueur)",
          "correct": false,
          "feedback": "Erreur : `*` ne calcule pas la longueur.\n"
        },
        {
          "text": "`ab3`",
          "correct": false,
          "feedback": "Erreur : `*` ne convertit pas l'entier en\nchaîne pour concaténer.\n"
        }
      ],
      "explanation": "Comme pour `+`, `*` est surchargé. Sur des\nlistes : `[0] * 5 == [0, 0, 0, 0, 0]`. Très\nutile pour initialiser un tableau."
    },
    {
      "id": "q15",
      "difficulty": 2,
      "skills": [
        "input"
      ],
      "title": "Saisie utilisateur",
      "statement": "Que renvoie `input(\"Âge ?\")` après que\nl'utilisateur a tapé `17` ?",
      "options": [
        {
          "text": "Le flottant `17.0`",
          "correct": false,
          "feedback": "Erreur : pas de conversion automatique.\n"
        },
        {
          "text": "Le booléen `True`",
          "correct": false,
          "feedback": "La fonction `input()` renvoie\nsystématiquement une chaîne\nde caractères, indépendamment\nde ce que l'utilisateur saisit.\nAucune conversion en booléen\nn'est effectuée.\n"
        },
        {
          "text": "L'entier `17`",
          "correct": false,
          "feedback": "Erreur : `input` renvoie **toujours** une\nchaîne, même si l'utilisateur a tapé un\nnombre.\n"
        },
        {
          "text": "La chaîne `\"17\"`",
          "correct": true,
          "feedback": "Bonne réponse : pour obtenir un entier, il\nfaut convertir : `int(input(\"Âge ?\"))`.\n"
        }
      ],
      "explanation": "Piège classique : `n = input(); n + 1` lève\n`TypeError` car `n` est une chaîne. Penser à\nconvertir explicitement."
    },
    {
      "id": "q16",
      "difficulty": 2,
      "skills": [
        "comparaison"
      ],
      "title": "Comparaison",
      "statement": "Que renvoie `2 < 3 < 5` en Python ?",
      "options": [
        {
          "text": "`False`",
          "correct": false,
          "feedback": "Erreur : 2 < 3 et 3 < 5 sont les deux\nvraies.\n"
        },
        {
          "text": "`5`",
          "correct": false,
          "feedback": "Erreur : la comparaison renvoie un booléen,\npas une valeur.\n"
        },
        {
          "text": "Une erreur de syntaxe",
          "correct": false,
          "feedback": "Erreur : Python autorise la comparaison\nchaînée.\n"
        },
        {
          "text": "`True` (équivalent à `2 < 3 and 3 < 5`)",
          "correct": true,
          "feedback": "Bonne réponse : Python permet d'enchaîner\nles comparaisons. C'est lisible et naturel\n(« 3 est entre 2 et 5 »).\n"
        }
      ],
      "explanation": "Particularité Python (rare dans les autres\nlangages) : `a < b < c` est correctement\ninterprété comme `a < b and b < c`."
    },
    {
      "id": "q17",
      "difficulty": 2,
      "skills": [
        "bool-conversion"
      ],
      "title": "Conversion en booléen",
      "statement": "Que renvoie `bool(0)` ?",
      "options": [
        {
          "text": "`True`",
          "correct": false,
          "feedback": "Erreur : 0 est considéré comme faux en\nPython.\n"
        },
        {
          "text": "`0`",
          "correct": false,
          "feedback": "Erreur : `bool(...)` renvoie un booléen,\npas le même entier.\n"
        },
        {
          "text": "`False`",
          "correct": true,
          "feedback": "Bonne réponse : par convention, 0 (entier\nou flottant) est faux ; tout autre nombre\nest vrai. La chaîne vide `\"\"` et la liste\nvide `[]` sont aussi fausses.\n"
        },
        {
          "text": "Une erreur",
          "correct": false,
          "feedback": "Erreur : conversion valide.\n"
        }
      ],
      "explanation": "Valeurs **fausses** en Python : `False`, `0`,\n`0.0`, `\"\"`, `[]`, `{}`, `None`. Tout le reste\nest vrai. Permet d'écrire `if liste:` au lieu\nde `if len(liste) > 0:`."
    },
    {
      "id": "q18",
      "difficulty": 2,
      "skills": [
        "string-len"
      ],
      "title": "Longueur de chaîne",
      "statement": "Que renvoie `len(\"hello\")` ?",
      "options": [
        {
          "text": "`hello`",
          "correct": false,
          "feedback": "Erreur : `len` renvoie un entier, pas la\nchaîne elle-même.\n"
        },
        {
          "text": "1",
          "correct": false,
          "feedback": "Erreur : `len` ne renvoie pas le nombre de\nmots ou de phrases.\n"
        },
        {
          "text": "5.0",
          "correct": false,
          "feedback": "Erreur : `len` renvoie un entier, pas un\nflottant.\n"
        },
        {
          "text": "5",
          "correct": true,
          "feedback": "Bonne réponse : `len` renvoie le nombre\nde caractères. Pour une liste, c'est le\nnombre d'éléments.\n"
        }
      ],
      "explanation": "`len` est polymorphe : marche sur les chaînes,\nlistes, tuples, dictionnaires, ensembles,\nfichiers... Toujours en O(1) pour ces types."
    },
    {
      "id": "q19",
      "difficulty": 2,
      "skills": [
        "type-conversion-int-float"
      ],
      "title": "Conversion float → int",
      "statement": "Que renvoie `int(3.9)` ?",
      "options": [
        {
          "text": "4 (arrondi)",
          "correct": false,
          "feedback": "Erreur : `int()` ne fait pas d'arrondi\nmathématique.\n"
        },
        {
          "text": "Une erreur",
          "correct": false,
          "feedback": "Erreur : conversion valide.\n"
        },
        {
          "text": "3 (troncature vers 0)",
          "correct": true,
          "feedback": "Bonne réponse : `int(x)` applique une\ntroncature vers 0. `int(-3.9)` donnerait\n`-3`, pas `-4`. Pour arrondir\nmathématiquement, utiliser `round`.\n"
        },
        {
          "text": "3.9",
          "correct": false,
          "feedback": "Erreur : `int()` renvoie un entier, pas un\nflottant.\n"
        }
      ],
      "explanation": "Distinguer quatre fonctions : `int(3.9) = 3`\n(troncature vers zéro) ; `round(3.9) = 4`\n(arrondi au plus proche, avec départage au\npair seulement pour les valeurs à mi-chemin\ndu type $0{,}5$) ; `math.floor(3.9) = 3`\n(partie entière inférieure) ;\n`math.ceil(3.9) = 4` (partie entière\nsupérieure)."
    },
    {
      "id": "q20",
      "difficulty": 2,
      "skills": [
        "string-indexation"
      ],
      "title": "Indexation de chaîne",
      "statement": "Que renvoie `\"hello\"[0]` ?",
      "options": [
        {
          "text": "`h`",
          "correct": true,
          "feedback": "Bonne réponse : Python indexe à partir de\n**0**. Le premier caractère est à l'indice\n0, le dernier à l'indice n-1.\n"
        },
        {
          "text": "`e`",
          "correct": false,
          "feedback": "Erreur : à l'indice 1, pas 0.\n"
        },
        {
          "text": "Une erreur",
          "correct": false,
          "feedback": "Erreur : la syntaxe est valide.\n"
        },
        {
          "text": "`hello`",
          "correct": false,
          "feedback": "Erreur : `[0]` extrait un seul caractère,\npas la chaîne entière.\n"
        }
      ],
      "explanation": "Indexation négative : `\"hello\"[-1] = 'o'`\n(dernier). Tranche : `\"hello\"[1:4] = 'ell'`."
    },
    {
      "id": "q21",
      "difficulty": 3,
      "skills": [
        "precision-float"
      ],
      "title": "Précision flottante",
      "statement": "Que renvoie `0.1 + 0.2 == 0.3` ?",
      "options": [
        {
          "text": "`0.3`",
          "correct": false,
          "feedback": "Erreur : une comparaison renvoie toujours\nun booléen.\n"
        },
        {
          "text": "`True`",
          "correct": false,
          "feedback": "Erreur : à cause de la représentation IEEE\n754, `0.1 + 0.2` ne donne pas exactement\n`0.3`.\n"
        },
        {
          "text": "Une erreur",
          "correct": false,
          "feedback": "Erreur : pas d'erreur, juste un résultat\ncontre-intuitif.\n"
        },
        {
          "text": "`False`",
          "correct": true,
          "feedback": "Bonne réponse : `0.1 + 0.2` vaut en réalité\n`0.30000000000000004`. C'est un piège\nclassique des flottants.\n"
        }
      ],
      "explanation": "Bonne pratique : ne jamais comparer des\nflottants avec `==`. Utiliser\n`abs(a - b) < epsilon` pour une comparaison à\nε près, ou le module `math.isclose`."
    },
    {
      "id": "q22",
      "difficulty": 3,
      "skills": [
        "puissance"
      ],
      "title": "Opérateur puissance",
      "statement": "Que vaut `2 ** 10` ?",
      "options": [
        {
          "text": "100",
          "correct": false,
          "feedback": "Erreur : ce serait `10²`, pas `2¹⁰`.\n"
        },
        {
          "text": "1024 (= 2¹⁰)",
          "correct": true,
          "feedback": "Bonne réponse : `**` est l'opérateur\npuissance. À retenir : `2¹⁰ = 1024`,\n`2²⁰ ≈ 10⁶`, `2³⁰ ≈ 10⁹`.\n"
        },
        {
          "text": "Une erreur",
          "correct": false,
          "feedback": "Erreur : `**` est valide.\n"
        },
        {
          "text": "20",
          "correct": false,
          "feedback": "Erreur : confusion entre `*` (multiplication)\net `**` (puissance).\n"
        }
      ],
      "explanation": "Syntaxe `a ** b` (parfois écrite `pow(a, b)`).\nAstuce : `2 ** 0.5` donne la racine carrée de\n2."
    },
    {
      "id": "q23",
      "difficulty": 3,
      "skills": [
        "debug-affectation"
      ],
      "title": "Affectation simultanée",
      "statement": "```python\na, b = 1, 2\na, b = b, a\n```\nQue valent `a` et `b` à la fin ?",
      "options": [
        {
          "text": "a = 2, b = 2",
          "correct": false,
          "feedback": "Erreur : ce serait le résultat **buggé**\nd'un échange séquentiel mal écrit. Python\ngère correctement.\n"
        },
        {
          "text": "Une erreur",
          "correct": false,
          "feedback": "Erreur : syntaxe valide.\n"
        },
        {
          "text": "a = 1, b = 2 (inchangé)",
          "correct": false,
          "feedback": "Erreur : il y a bien échange.\n"
        },
        {
          "text": "a = 2, b = 1 (échangés)",
          "correct": true,
          "feedback": "Bonne réponse : Python crée d'abord le\ntuple `(b, a) = (2, 1)`, puis le déballe\ndans `a, b`. Les deux changent\n**simultanément**, sans variable\ntemporaire.\n"
        }
      ],
      "explanation": "L'affectation simultanée est l'un des grands\natouts de Python pour la lisibilité. Beaucoup\nd'algorithmes (tri, recherche) en bénéficient."
    },
    {
      "id": "q24",
      "difficulty": 3,
      "skills": [
        "print-virgule"
      ],
      "title": "Print avec virgule",
      "statement": "Que renvoie `print(\"a\", \"b\", \"c\")` ?",
      "options": [
        {
          "text": "Affiche `[a, b, c]`",
          "correct": false,
          "feedback": "Erreur : aucun crochet ajouté\nautomatiquement.\n"
        },
        {
          "text": "Affiche `abc`",
          "correct": false,
          "feedback": "Erreur : par défaut, `print` insère un\nespace entre les arguments.\n"
        },
        {
          "text": "Affiche `a b c` (espaces entre les arguments)",
          "correct": true,
          "feedback": "Bonne réponse : le séparateur par défaut\nest un espace. On peut le changer avec\n`sep=\"...\"`. Ex. : `print(\"a\", \"b\",\nsep=\" - \")` affiche `a - b`.\n"
        },
        {
          "text": "Lève une exception",
          "correct": false,
          "feedback": "Erreur : `print` accepte plusieurs\narguments.\n"
        }
      ],
      "explanation": "Paramètres utiles : `sep=\"...\"` (séparateur\nentre arguments) et `end=\"...\"` (à la fin, par\ndéfaut `\\n`). Pour ne pas aller à la ligne :\n`print(\"...\", end=\"\")`."
    },
    {
      "id": "q25",
      "difficulty": 3,
      "skills": [
        "synthese"
      ],
      "title": "Synthèse",
      "statement": "Parmi les affirmations suivantes, laquelle est\n**fausse** ?",
      "options": [
        {
          "text": "Python est typé dynamiquement",
          "correct": false,
          "feedback": "Vrai : une variable peut changer de type.\n"
        },
        {
          "text": "La chaîne vide `\"\"` est considérée comme vraie dans une condition",
          "correct": true,
          "feedback": "Faux (donc bonne réponse) : la chaîne vide\nest **fausse** en contexte booléen, comme\n`0`, `[]`, `{}`, `None`.\n"
        },
        {
          "text": "`/` produit toujours un flottant en Python 3",
          "correct": false,
          "feedback": "Vrai : différence par rapport à Python 2.\n"
        },
        {
          "text": "Les indices Python commencent à 0",
          "correct": false,
          "feedback": "Vrai : convention standard en informatique.\n"
        }
      ],
      "explanation": "Mnémonique des valeurs fausses : « tout ce\nqui est vide ou nul ». Cela permet des\nidiomes concis comme `if liste:` (= « si la\nliste n'est pas vide »)."
    },
    {
      "id": "q26",
      "difficulty": 1,
      "skills": [
        "echange",
        "affectation-multiple"
      ],
      "title": "Échanger deux variables en Python",
      "statement": "Quelle est la façon la plus idiomatique d'échanger\nles valeurs de deux variables `a` et `b` en Python ?",
      "options": [
        {
          "text": "`swap(a, b)`",
          "correct": false,
          "feedback": "Erreur : il n'existe pas de fonction native\n`swap` en Python. De plus, comme les paramètres\nsont passés par référence d'objet, une telle\nfonction ne pourrait pas réaffecter les\nvariables d'origine.\n"
        },
        {
          "text": "`a = b = a`",
          "correct": false,
          "feedback": "Erreur : cette instruction affecte la valeur\nactuelle de `a` à `b`, puis cette même valeur à\n`a` (sans changement). Aucun échange n'est\neffectué.\n"
        },
        {
          "text": "`a = b` puis `b = a`",
          "correct": false,
          "feedback": "Erreur : ce code ne réalise pas un échange. Après\nla première instruction, `a` perd sa valeur\nd'origine et prend celle de `b`. La seconde\ninstruction recopie alors `b` dans... `b`. Les\ndeux variables se retrouvent égales à la valeur\ninitiale de `b`.\n"
        },
        {
          "text": "`a, b = b, a`",
          "correct": true,
          "feedback": "Bonne réponse : Python évalue d'abord le\nmembre de droite (le couple `(b, a)`) puis\naffecte simultanément les deux composantes aux\nvariables de gauche. Aucune variable temporaire\nn'est nécessaire.\n"
        }
      ],
      "explanation": "L'affectation multiple `a, b = b, a` repose sur les\n*p-uplets* implicites : Python crée d'abord le\ncouple `(b, a)` côté droit, puis le déballe à\ngauche. Cette construction est plus claire et plus\ncourte que la version classique avec variable\ntemporaire (`tmp = a; a = b; b = tmp`)."
    },
    {
      "id": "q27",
      "difficulty": 2,
      "skills": [
        "f-string",
        "formatage"
      ],
      "title": "Affichage formaté avec une f-string",
      "statement": "On exécute le code suivant :\n\n```python\nprix = 12.5\nquantite = 3\nprint(f\"Total : {prix * quantite} €\")\n```\n\nQue va afficher le programme ?",
      "options": [
        {
          "text": "`Total : 37.5 €`",
          "correct": true,
          "feedback": "Bonne réponse : la f-string remplace\n`{prix * quantite}` par le résultat de\nl'expression évaluée, soit\n$12{,}5 \\times 3 = 37{,}5$. Le reste de la\nchaîne est laissé tel quel.\n"
        },
        {
          "text": "`Total : 12.5 * 3 €`",
          "correct": false,
          "feedback": "Erreur : Python évalue toujours l'expression\nentre accolades, il n'affiche jamais l'opération\nen clair. Le résultat affiché est\n$37{,}5$, pas la formule.\n"
        },
        {
          "text": "`Total : {prix * quantite} €`",
          "correct": false,
          "feedback": "Erreur : la lettre `f` placée devant la chaîne\nactive le formatage : les expressions entre\naccolades sont **évaluées** avant l'affichage.\nSans le préfixe `f`, on aurait au contraire ce\nrendu littéral.\n"
        },
        {
          "text": "Le code provoque une erreur de syntaxe",
          "correct": false,
          "feedback": "Erreur : la syntaxe est correcte. Les f-strings\nsont disponibles depuis Python $3{.}6$ et sont\naujourd'hui le moyen le plus simple d'insérer\ndes valeurs dans une chaîne.\n"
        }
      ],
      "explanation": "Quelques options pratiques des f-strings :\n`f\"{x:.2f}\"` arrondit à deux chiffres après la\nvirgule, `f\"{x:>10}\"` aligne à droite sur dix\ncaractères, `f\"{x=}\"` affiche à la fois le nom et\nla valeur (`x=37.5`). C'est une syntaxe à privilégier\npour la plupart des affichages courants."
    },
    {
      "id": "q28",
      "difficulty": 2,
      "skills": [
        "methodes-chaine",
        "upper",
        "lower"
      ],
      "title": "Méthodes de chaîne",
      "statement": "Que vaut l'expression `\"NSI\".lower()` en Python ?",
      "options": [
        {
          "text": "`'Nsi'`",
          "correct": false,
          "feedback": "Erreur : ce serait l'effet de la méthode\n`capitalize`, qui met seulement la première\nlettre en majuscule et les autres en minuscules.\nLa méthode `lower` agit sur tous les caractères.\n"
        },
        {
          "text": "La méthode `lower` n'existe pas",
          "correct": false,
          "feedback": "Erreur : `lower` est une méthode standard des\nchaînes Python, présente depuis les premières\nversions du langage. Elle est très utilisée pour\ncomparer des chaînes sans tenir compte de la\ncasse.\n"
        },
        {
          "text": "`'nsi'`",
          "correct": true,
          "feedback": "Bonne réponse : `lower` renvoie une **nouvelle\nchaîne** où toutes les lettres ont été passées\nen minuscules. La chaîne d'origine n'est pas\nmodifiée (les chaînes Python sont immuables).\n"
        },
        {
          "text": "`'NSI'`",
          "correct": false,
          "feedback": "Erreur : la méthode `lower` transforme la chaîne\nen minuscules. Elle ne peut donc pas renvoyer la\nchaîne d'origine inchangée.\n"
        }
      ],
      "explanation": "Méthodes de chaîne fréquentes : `upper()` (tout en\nmajuscules), `lower()` (tout en minuscules),\n`strip()` (supprime les espaces de début et de fin),\n`replace(a, b)` (remplace `a` par `b`),\n`split(sep)` (découpe selon un séparateur). Comme\nles chaînes sont immuables, ces méthodes renvoient\ntoujours une **nouvelle** chaîne."
    },
    {
      "id": "q29",
      "difficulty": 3,
      "skills": [
        "identite",
        "egalite",
        "is"
      ],
      "title": "Différence entre `==` et `is`",
      "statement": "En Python, quelle est la différence entre les\nopérateurs `==` et `is` ?",
      "options": [
        {
          "text": "`==` renvoie un nombre, `is` renvoie un booléen",
          "correct": false,
          "feedback": "Erreur : les deux opérateurs renvoient un\nbooléen (`True` ou `False`). Aucun ne produit\nde valeur numérique.\n"
        },
        {
          "text": "Les deux sont strictement équivalents",
          "correct": false,
          "feedback": "Erreur : ils ne testent pas la même chose. La\nconfusion entre les deux est une source classique\nde bugs subtils, en particulier sur les listes\net les dictionnaires.\n"
        },
        {
          "text": "`==` ne fonctionne que sur les nombres ; `is` ne fonctionne que sur les chaînes",
          "correct": false,
          "feedback": "Erreur : les deux opérateurs s'appliquent à\n**toutes** les valeurs Python. La distinction\nentre eux est sémantique (égalité de valeur vs\nidentité d'objet), pas typologique.\n"
        },
        {
          "text": "`==` compare les valeurs ; `is` teste si les deux références désignent le même objet en mémoire",
          "correct": true,
          "feedback": "Bonne réponse : deux listes peuvent contenir les\nmêmes valeurs (`[1, 2] == [1, 2]` vaut `True`)\ntout en étant des objets distincts en mémoire\n(`[1, 2] is [1, 2]` vaut `False`). L'opérateur\n`is` est plus strict que `==`.\n"
        }
      ],
      "explanation": "Recommandation pratique : utiliser `==` pour\ncomparer des valeurs ordinaires, et réserver `is`\naux comparaisons à des **singletons** (`x is None`,\n`x is True`, `x is False`). La référence avec\n`None` est en effet unique en mémoire, donc `is`\nest exact et plus rapide."
    }
  ]
}