{
  "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.",
    "parties": [
      {
        "id": "variables",
        "title": "Variables et affectation"
      },
      {
        "id": "types",
        "title": "Types et conversions"
      },
      {
        "id": "operations",
        "title": "Opérations et opérateurs"
      },
      {
        "id": "chaines",
        "title": "Chaînes de caractères"
      }
    ],
    "prerequisites": [],
    "references": []
  },
  "questions": [
    {
      "id": "q01",
      "difficulty": 1,
      "skills": [
        "affectation"
      ],
      "title": "Affectation",
      "partie": "variables",
      "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",
      "partie": "types",
      "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",
      "partie": "types",
      "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` n'est pas un type natif de\nPython ; le type 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 limitée**. `0.1 + 0.2` ne donne pas exactement\n`0.3` mais `0.30000000000000004`, car ces nombres\nn'ont pas d'écriture binaire exacte."
    },
    {
      "id": "q04",
      "difficulty": 1,
      "skills": [
        "type-str"
      ],
      "title": "Type chaîne",
      "partie": "types",
      "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",
      "partie": "types",
      "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 obligatoire**. `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",
        "int"
      ],
      "title": "Conversion en entier",
      "partie": "types",
      "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`.",
      "variants": [
        {
          "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`."
        },
        {
          "statement": "Que renvoie `int(\"7\")` ?",
          "options": [
            {
              "text": "La chaîne `\"7\"`",
              "correct": false,
              "feedback": "Erreur : `int(...)` renvoie un entier, pas\nune chaîne.\n"
            },
            {
              "text": "L'entier `7`",
              "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 : `\"7\"` est convertible. Une chaîne\ncomme `\"abc\"` lèverait `ValueError`.\n"
            },
            {
              "text": "Le flottant `7.0`",
              "correct": false,
              "feedback": "Erreur : `int` produit un entier, pas un\nflottant. Utiliser `float(\"7\")` 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`."
        },
        {
          "statement": "Que renvoie `int(\"2026\")` ?",
          "options": [
            {
              "text": "La chaîne `\"2026\"`",
              "correct": false,
              "feedback": "Erreur : `int(...)` renvoie un entier, pas\nune chaîne.\n"
            },
            {
              "text": "L'entier `2026`",
              "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 : `\"2026\"` est convertible. Une chaîne\ncomme `\"abc\"` lèverait `ValueError`.\n"
            },
            {
              "text": "Le flottant `2026.0`",
              "correct": false,
              "feedback": "Erreur : `int` produit un entier, pas un\nflottant. Utiliser `float(\"2026\")` 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": [
        "division",
        "flottant"
      ],
      "title": "Opérateur de division",
      "partie": "operations",
      "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).",
      "variants": [
        {
          "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)."
        },
        {
          "statement": "Que renvoie `11 / 4` en Python 3 ?",
          "options": [
            {
              "text": "2",
              "correct": false,
              "feedback": "Erreur : c'est la division entière (`//`).\n"
            },
            {
              "text": "Une erreur",
              "correct": false,
              "feedback": "Erreur : la syntaxe est valide.\n"
            },
            {
              "text": "3",
              "correct": false,
              "feedback": "Erreur : pas d'arrondi.\n"
            },
            {
              "text": "2.75",
              "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)."
        },
        {
          "statement": "Que renvoie `7 / 4` en Python 3 ?",
          "options": [
            {
              "text": "1",
              "correct": false,
              "feedback": "Erreur : c'est la division entière (`//`).\n"
            },
            {
              "text": "Une erreur",
              "correct": false,
              "feedback": "Erreur : la syntaxe est valide.\n"
            },
            {
              "text": "2",
              "correct": false,
              "feedback": "Erreur : pas d'arrondi.\n"
            },
            {
              "text": "1.75",
              "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",
      "partie": "operations",
      "statement": "Que renvoie `7 // 2` ?",
      "options": [
        {
          "text": "1",
          "correct": false,
          "feedback": "Erreur : 1 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`.",
      "variants": [
        {
          "statement": "Que renvoie `7 // 2` ?",
          "options": [
            {
              "text": "1",
              "correct": false,
              "feedback": "Erreur : 1 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`."
        },
        {
          "statement": "Que renvoie `22 // 5` ?",
          "options": [
            {
              "text": "2",
              "correct": false,
              "feedback": "Erreur : 2 est le reste (`%`), pas le quotient.\n"
            },
            {
              "text": "5",
              "correct": false,
              "feedback": "Erreur : pas d'arrondi à l'entier supérieur,\nmais troncature vers le bas.\n"
            },
            {
              "text": "4.4",
              "correct": false,
              "feedback": "Erreur : c'est la division **flottante**\n(`/`).\n"
            },
            {
              "text": "4",
              "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`."
        },
        {
          "statement": "Que renvoie `23 // 4` ?",
          "options": [
            {
              "text": "3",
              "correct": false,
              "feedback": "Erreur : 3 est le reste (`%`), pas le quotient.\n"
            },
            {
              "text": "6",
              "correct": false,
              "feedback": "Erreur : pas d'arrondi à l'entier supérieur,\nmais troncature vers le bas.\n"
            },
            {
              "text": "5.75",
              "correct": false,
              "feedback": "Erreur : c'est la division **flottante**\n(`/`).\n"
            },
            {
              "text": "5",
              "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",
      "partie": "operations",
      "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 n'est pas un multiple de 2, son reste\nn'est pas nul.\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.",
      "variants": [
        {
          "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 n'est pas un multiple de 2, son reste\nn'est pas nul.\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."
        },
        {
          "statement": "Que renvoie `17 % 5` ?",
          "options": [
            {
              "text": "2",
              "correct": true,
              "feedback": "Bonne réponse : `%` calcule le **reste**\nde la division entière. 17 = 3 × 5 + 2, donc\n17 % 5 = 2.\n"
            },
            {
              "text": "3.4",
              "correct": false,
              "feedback": "Erreur : c'est `/`, pas `%`.\n"
            },
            {
              "text": "0",
              "correct": false,
              "feedback": "Erreur : 17 n'est pas un multiple de 5, son reste\nn'est pas nul.\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."
        },
        {
          "statement": "Que renvoie `23 % 4` ?",
          "options": [
            {
              "text": "3",
              "correct": true,
              "feedback": "Bonne réponse : `%` calcule le **reste**\nde la division entière. 23 = 5 × 4 + 3, donc\n23 % 4 = 3.\n"
            },
            {
              "text": "5.75",
              "correct": false,
              "feedback": "Erreur : c'est `/`, pas `%`.\n"
            },
            {
              "text": "0",
              "correct": false,
              "feedback": "Erreur : 23 n'est pas un multiple de 4, son reste\nn'est pas nul.\n"
            },
            {
              "text": "5",
              "correct": false,
              "feedback": "Erreur : 5 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",
      "partie": "variables",
      "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 aussi utile pour la mise au point d'un\nprogramme : afficher la valeur d'une variable aide\nà repérer une erreur."
    },
    {
      "id": "q11",
      "difficulty": 2,
      "skills": [
        "type-dynamique"
      ],
      "title": "Typage dynamique",
      "partie": "variables",
      "statement": "```python\nx = 5\nx = \"hello\"\n```\nCette suite d'instructions est-elle valide ?",
      "options": [
        {
          "text": "Non, il faut d'abord redéclarer la variable `x` avec son nouveau type",
          "correct": false,
          "feedback": "Erreur : aucune « redéclaration » n'existe\nen Python, une simple affectation suffit.\n"
        },
        {
          "text": "Oui, mais Python affiche un avertissement de changement de type",
          "correct": false,
          "feedback": "Erreur : aucun avertissement n'est émis par\ndéfaut.\n"
        },
        {
          "text": "Non, `x` est figé en entier dès sa première affectation",
          "correct": false,
          "feedback": "Erreur : ce serait le cas dans un langage à\n**typage statique** (Java, C++, Rust),\nmais pas en Python.\n"
        },
        {
          "text": "Oui : le typage de Python est dynamique",
          "correct": true,
          "feedback": "Bonne réponse : une variable peut désigner\nsuccessivement des objets de types\ndifférents, Python autorise cette\nréaffectation. C'est puissant mais source\nde bugs subtils.\n"
        }
      ],
      "explanation": "Avec le typage dynamique, on gagne en souplesse\nmais on perd en sûreté : une erreur de type\nn'apparaît qu'au moment de l'exécution."
    },
    {
      "id": "q12",
      "difficulty": 2,
      "skills": [
        "conversion-erreur"
      ],
      "title": "Conversion qui plante",
      "partie": "types",
      "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'`. Avant de convertir une saisie, on\nvérifie donc qu'elle ne contient que des\nchiffres.\n"
        }
      ],
      "explanation": "Bonne pratique : vérifier qu'une saisie ne\ncontient que des chiffres avant de la convertir.\n```python\ns = input()\nok = len(s) > 0\nfor c in s:\n    if c not in \"0123456789\":\n        ok = False\nif ok:\n    n = int(s)\nelse:\n    print(\"Pas un entier\")\n```\nLa gestion des exceptions, qui permet de\nrattraper l'erreur après coup, est au programme\nde terminale."
    },
    {
      "id": "q13",
      "difficulty": 2,
      "skills": [
        "concatenation"
      ],
      "title": "Concaténation",
      "partie": "operations",
      "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": "`+` a un sens différent selon le type : addition\npour les nombres, concaténation pour les chaînes\net les listes. Mais pas de mélange : `\"a\" + 5`\nlève `TypeError`."
    },
    {
      "id": "q14",
      "difficulty": 2,
      "skills": [
        "repetition"
      ],
      "title": "Répétition de chaîne",
      "partie": "operations",
      "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",
      "partie": "variables",
      "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",
      "partie": "operations",
      "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`",
          "correct": true,
          "feedback": "Bonne réponse : Python permet d'enchaîner\nles comparaisons : `2 < 3 < 5` équivaut à\n`2 < 3 and 3 < 5`. 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",
      "partie": "types",
      "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.\n"
        },
        {
          "text": "Une erreur",
          "correct": false,
          "feedback": "Erreur : conversion valide.\n"
        }
      ],
      "explanation": "`bool` convertit un nombre en booléen : `0` et\n`0.0` donnent `False`, tout autre nombre donne\n`True`. On retrouve la convention des valeurs\nbooléennes 0 et 1."
    },
    {
      "id": "q18",
      "difficulty": 2,
      "skills": [
        "string-len"
      ],
      "title": "Longueur de chaîne",
      "partie": "chaines",
      "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` s'applique aussi aux listes, aux p-uplets\net aux dictionnaires : elle renvoie toujours un\nnombre d'éléments."
    },
    {
      "id": "q19",
      "difficulty": 2,
      "skills": [
        "conversion",
        "troncature"
      ],
      "title": "Conversion float → int",
      "partie": "types",
      "statement": "Que renvoie `int(3.9)` ?",
      "options": [
        {
          "text": "4",
          "correct": false,
          "feedback": "Erreur : `int()` ne fait pas d'arrondi\nmathématique ; c'est `round(3.9)` qui\ndonnerait 4.\n"
        },
        {
          "text": "Une erreur",
          "correct": false,
          "feedback": "Erreur : conversion valide.\n"
        },
        {
          "text": "3",
          "correct": true,
          "feedback": "Bonne réponse : `int(x)` applique une\n**troncature vers 0**, pas un arrondi.\n`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)` vaut 3\n(troncature vers zéro) ; `round(3.9)` vaut 4\n(arrondi au plus proche) ; `math.floor(3.9)`\nvaut 3 (partie entière inférieure) ;\n`math.ceil(3.9)` vaut 4 (partie entière\nsupérieure).",
      "variants": [
        {
          "statement": "Que renvoie `int(3.9)` ?",
          "options": [
            {
              "text": "4",
              "correct": false,
              "feedback": "Erreur : `int()` ne fait pas d'arrondi\nmathématique ; c'est `round(3.9)` qui\ndonnerait 4.\n"
            },
            {
              "text": "Une erreur",
              "correct": false,
              "feedback": "Erreur : conversion valide.\n"
            },
            {
              "text": "3",
              "correct": true,
              "feedback": "Bonne réponse : `int(x)` applique une\n**troncature vers 0**, pas un arrondi.\n`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)` vaut 3\n(troncature vers zéro) ; `round(3.9)` vaut 4\n(arrondi au plus proche) ; `math.floor(3.9)`\nvaut 3 (partie entière inférieure) ;\n`math.ceil(3.9)` vaut 4 (partie entière\nsupérieure)."
        },
        {
          "statement": "Que renvoie `int(7.6)` ?",
          "options": [
            {
              "text": "8",
              "correct": false,
              "feedback": "Erreur : `int()` ne fait pas d'arrondi\nmathématique ; c'est `round(7.6)` qui\ndonnerait 8.\n"
            },
            {
              "text": "Une erreur",
              "correct": false,
              "feedback": "Erreur : conversion valide.\n"
            },
            {
              "text": "7",
              "correct": true,
              "feedback": "Bonne réponse : `int(x)` applique une\n**troncature vers 0**, pas un arrondi.\n`int(-7.6)` donnerait\n`-7`, pas `-8`. Pour arrondir\nmathématiquement, utiliser `round`.\n"
            },
            {
              "text": "7.6",
              "correct": false,
              "feedback": "Erreur : `int()` renvoie un entier, pas un\nflottant.\n"
            }
          ],
          "explanation": "Distinguer quatre fonctions : `int(7.6)` vaut 7\n(troncature vers zéro) ; `round(7.6)` vaut 8\n(arrondi au plus proche) ; `math.floor(7.6)`\nvaut 7 (partie entière inférieure) ;\n`math.ceil(7.6)` vaut 8 (partie entière\nsupérieure)."
        },
        {
          "statement": "Que renvoie `int(12.6)` ?",
          "options": [
            {
              "text": "13",
              "correct": false,
              "feedback": "Erreur : `int()` ne fait pas d'arrondi\nmathématique ; c'est `round(12.6)` qui\ndonnerait 13.\n"
            },
            {
              "text": "Une erreur",
              "correct": false,
              "feedback": "Erreur : conversion valide.\n"
            },
            {
              "text": "12",
              "correct": true,
              "feedback": "Bonne réponse : `int(x)` applique une\n**troncature vers 0**, pas un arrondi.\n`int(-12.6)` donnerait\n`-12`, pas `-13`. Pour arrondir\nmathématiquement, utiliser `round`.\n"
            },
            {
              "text": "12.6",
              "correct": false,
              "feedback": "Erreur : `int()` renvoie un entier, pas un\nflottant.\n"
            }
          ],
          "explanation": "Distinguer quatre fonctions : `int(12.6)` vaut 12\n(troncature vers zéro) ; `round(12.6)` vaut 13\n(arrondi au plus proche) ; `math.floor(12.6)`\nvaut 12 (partie entière inférieure) ;\n`math.ceil(12.6)` vaut 13 (partie entière\nsupérieure)."
        }
      ]
    },
    {
      "id": "q20",
      "difficulty": 2,
      "skills": [
        "string-indexation"
      ],
      "title": "Indexation de chaîne",
      "partie": "chaines",
      "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",
      "partie": "types",
      "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 `==`. On teste plutôt\n`abs(a - b) < epsilon`, avec `epsilon` un petit\nseuil comme `1e-9` : ainsi\n`abs(0.1 + 0.2 - 0.3) < 1e-9` vaut `True`."
    },
    {
      "id": "q22",
      "difficulty": 3,
      "skills": [
        "puissance",
        "operateurs"
      ],
      "title": "Opérateur puissance",
      "partie": "operations",
      "statement": "Que vaut `2 ** 10` ?",
      "options": [
        {
          "text": "100",
          "correct": false,
          "feedback": "Erreur : ce serait `10²`, pas `2` élevé à la puissance `10`.\n"
        },
        {
          "text": "1024",
          "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.",
      "variants": [
        {
          "statement": "Que vaut `2 ** 10` ?",
          "options": [
            {
              "text": "100",
              "correct": false,
              "feedback": "Erreur : ce serait `10²`, pas `2` élevé à la puissance `10`.\n"
            },
            {
              "text": "1024",
              "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."
        },
        {
          "statement": "Que vaut `2 ** 8` ?",
          "options": [
            {
              "text": "64",
              "correct": false,
              "feedback": "Erreur : ce serait `8²`, pas `2` élevé à la puissance `8`.\n"
            },
            {
              "text": "256",
              "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": "16",
              "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."
        },
        {
          "statement": "Que vaut `2 ** 12` ?",
          "options": [
            {
              "text": "144",
              "correct": false,
              "feedback": "Erreur : ce serait `12²`, pas `2` élevé à la puissance `12`.\n"
            },
            {
              "text": "4096",
              "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": "24",
              "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": [
        "affectation-simultanee",
        "echange"
      ],
      "title": "Affectation simultanée",
      "partie": "variables",
      "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.",
      "variants": [
        {
          "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."
        },
        {
          "statement": "```python\na, b = 5, 9\na, b = b, a\n```\nQue valent `a` et `b` à la fin ?",
          "options": [
            {
              "text": "a = 9, b = 9",
              "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 = 5, b = 9 (inchangé)",
              "correct": false,
              "feedback": "Erreur : il y a bien échange.\n"
            },
            {
              "text": "a = 9, b = 5 (échangés)",
              "correct": true,
              "feedback": "Bonne réponse : Python crée d'abord le\ntuple `(b, a) = (9, 5)`, 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."
        },
        {
          "statement": "```python\na, b = 3, 8\na, b = b, a\n```\nQue valent `a` et `b` à la fin ?",
          "options": [
            {
              "text": "a = 8, b = 8",
              "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 = 3, b = 8 (inchangé)",
              "correct": false,
              "feedback": "Erreur : il y a bien échange.\n"
            },
            {
              "text": "a = 8, b = 3 (échangés)",
              "correct": true,
              "feedback": "Bonne réponse : Python crée d'abord le\ntuple `(b, a) = (8, 3)`, 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",
      "partie": "variables",
      "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`",
          "correct": true,
          "feedback": "Bonne réponse : `print` insère un espace\nentre ses arguments, le séparateur par\ndéfaut. 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",
      "partie": "chaines",
      "statement": "Parmi les affirmations suivantes, laquelle est\n**fausse** ?",
      "options": [
        {
          "text": "Le langage Python est typé dynamiquement",
          "correct": false,
          "feedback": "Vrai : une variable peut changer de type.\n"
        },
        {
          "text": "`0.1 + 0.2 == 0.3` vaut `True` en Python",
          "correct": true,
          "feedback": "Faux (donc bonne réponse) : `0.1 + 0.2` vaut\n`0.30000000000000004`, car ces nombres n'ont pas\nd'écriture binaire exacte. La comparaison vaut\ndonc `False`.\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": "À retenir : les flottants sont des valeurs\napprochées, on évite donc de tester leur égalité\navec `==`. On compare plutôt leur écart à une\npetite tolérance, par exemple\n`abs(a - b) < 0.000001`."
    },
    {
      "id": "q26",
      "difficulty": 1,
      "skills": [
        "echange",
        "affectation-multiple"
      ],
      "title": "Échanger deux variables en Python",
      "partie": "variables",
      "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.\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": [
        "chaine",
        "split"
      ],
      "title": "Découper une date",
      "partie": "chaines",
      "statement": "On exécute le code suivant :\n```python\ndate = \"12/09/2026\"\nmorceaux = date.split(\"/\")\nprint(morceaux)\n```\nQue va afficher le programme ?",
      "options": [
        {
          "text": "`[12, 9, 2026]`",
          "correct": false,
          "feedback": "Erreur : `split` ne convertit rien, les morceaux restent des\nchaînes de caractères. Pour obtenir le jour sous forme d'entier,\nil faut écrire `int(morceaux[0])`.\n"
        },
        {
          "text": "`['12/', '09/', '2026']`",
          "correct": false,
          "feedback": "Erreur : le séparateur sert à couper la chaîne et disparaît du\nrésultat. Aucun morceau ne contient la barre oblique.\n"
        },
        {
          "text": "`['12', '09', '2026']`",
          "correct": true,
          "feedback": "Bonne réponse : `split(\"/\")` découpe la chaîne à chaque barre\noblique et renvoie la liste des morceaux. Ce sont des chaînes :\nil faudrait `int` pour obtenir des nombres.\n"
        },
        {
          "text": "`'12092026'`",
          "correct": false,
          "feedback": "Erreur : `split` ne se contente pas de supprimer les barres\nobliques, il renvoie une **liste** de morceaux, pas une chaîne\nrecollée.\n"
        }
      ],
      "explanation": "`split(sep)` découpe une chaîne selon un séparateur et renvoie une\nliste de chaînes. C'est la méthode utilisée pour lire une ligne d'un\nfichier CSV, avant de convertir les valeurs numériques avec `int` ou\n`float`.",
      "variants": [
        {
          "statement": "On exécute le code suivant :\n```python\ndate = \"12/09/2026\"\nmorceaux = date.split(\"/\")\nprint(morceaux)\n```\nQue va afficher le programme ?",
          "options": [
            {
              "text": "`[12, 9, 2026]`",
              "correct": false,
              "feedback": "Erreur : `split` ne convertit rien, les morceaux restent des\nchaînes de caractères. Pour obtenir le jour sous forme d'entier,\nil faut écrire `int(morceaux[0])`.\n"
            },
            {
              "text": "`['12/', '09/', '2026']`",
              "correct": false,
              "feedback": "Erreur : le séparateur sert à couper la chaîne et disparaît du\nrésultat. Aucun morceau ne contient la barre oblique.\n"
            },
            {
              "text": "`['12', '09', '2026']`",
              "correct": true,
              "feedback": "Bonne réponse : `split(\"/\")` découpe la chaîne à chaque barre\noblique et renvoie la liste des morceaux. Ce sont des chaînes :\nil faudrait `int` pour obtenir des nombres.\n"
            },
            {
              "text": "`'12092026'`",
              "correct": false,
              "feedback": "Erreur : `split` ne se contente pas de supprimer les barres\nobliques, il renvoie une **liste** de morceaux, pas une chaîne\nrecollée.\n"
            }
          ],
          "explanation": "`split(sep)` découpe une chaîne selon un séparateur et renvoie une\nliste de chaînes. C'est la méthode utilisée pour lire une ligne d'un\nfichier CSV, avant de convertir les valeurs numériques avec `int` ou\n`float`."
        },
        {
          "statement": "On exécute le code suivant :\n```python\ndate = \"01/03/2027\"\nmorceaux = date.split(\"/\")\nprint(morceaux)\n```\nQue va afficher le programme ?",
          "options": [
            {
              "text": "`[1, 3, 2027]`",
              "correct": false,
              "feedback": "Erreur : `split` ne convertit rien, les morceaux restent des\nchaînes de caractères. Pour obtenir le jour sous forme d'entier,\nil faut écrire `int(morceaux[0])`.\n"
            },
            {
              "text": "`['01/', '03/', '2027']`",
              "correct": false,
              "feedback": "Erreur : le séparateur sert à couper la chaîne et disparaît du\nrésultat. Aucun morceau ne contient la barre oblique.\n"
            },
            {
              "text": "`['01', '03', '2027']`",
              "correct": true,
              "feedback": "Bonne réponse : `split(\"/\")` découpe la chaîne à chaque barre\noblique et renvoie la liste des morceaux. Ce sont des chaînes :\nil faudrait `int` pour obtenir des nombres.\n"
            },
            {
              "text": "`'01032027'`",
              "correct": false,
              "feedback": "Erreur : `split` ne se contente pas de supprimer les barres\nobliques, il renvoie une **liste** de morceaux, pas une chaîne\nrecollée.\n"
            }
          ],
          "explanation": "`split(sep)` découpe une chaîne selon un séparateur et renvoie une\nliste de chaînes. C'est la méthode utilisée pour lire une ligne d'un\nfichier CSV, avant de convertir les valeurs numériques avec `int` ou\n`float`."
        },
        {
          "statement": "On exécute le code suivant :\n```python\ndate = \"25/11/2025\"\nmorceaux = date.split(\"/\")\nprint(morceaux)\n```\nQue va afficher le programme ?",
          "options": [
            {
              "text": "`[25, 11, 2025]`",
              "correct": false,
              "feedback": "Erreur : `split` ne convertit rien, les morceaux restent des\nchaînes de caractères. Pour obtenir le jour sous forme d'entier,\nil faut écrire `int(morceaux[0])`.\n"
            },
            {
              "text": "`['25/', '11/', '2025']`",
              "correct": false,
              "feedback": "Erreur : le séparateur sert à couper la chaîne et disparaît du\nrésultat. Aucun morceau ne contient la barre oblique.\n"
            },
            {
              "text": "`['25', '11', '2025']`",
              "correct": true,
              "feedback": "Bonne réponse : `split(\"/\")` découpe la chaîne à chaque barre\noblique et renvoie la liste des morceaux. Ce sont des chaînes :\nil faudrait `int` pour obtenir des nombres.\n"
            },
            {
              "text": "`'25112025'`",
              "correct": false,
              "feedback": "Erreur : `split` ne se contente pas de supprimer les barres\nobliques, il renvoie une **liste** de morceaux, pas une chaîne\nrecollée.\n"
            }
          ],
          "explanation": "`split(sep)` découpe une chaîne selon un séparateur et renvoie une\nliste de chaînes. C'est la méthode utilisée pour lire une ligne d'un\nfichier CSV, avant de convertir les valeurs numériques avec `int` ou\n`float`."
        }
      ]
    },
    {
      "id": "q28",
      "difficulty": 2,
      "skills": [
        "methodes-chaine",
        "upper",
        "lower"
      ],
      "title": "Méthodes de chaîne",
      "partie": "chaines",
      "statement": "Que vaut l'expression `\"NSI\".lower()` en Python ?",
      "options": [
        {
          "text": "`'Nsi'`",
          "correct": false,
          "feedback": "Erreur : seule la première lettre serait alors\nen majuscule. La méthode `lower` passe tous les\ncaractères en minuscules.\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 chaîne** où toutes les lettres ont été passées\nen minuscules. La chaîne d'origine n'est pas\nmodifiée.\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`split(sep)` (découpe selon un séparateur). Ces\nméthodes renvoient une **nouvelle** chaîne, sans\nmodifier la chaîne d'origine."
    },
    {
      "id": "q29",
      "difficulty": 3,
      "skills": [
        "operateurs-booleens",
        "evaluation-sequentielle"
      ],
      "title": "Une division par zéro évitée",
      "partie": "operations",
      "statement": "On exécute le code suivant :\n\n```python\nx = 0\nprint(x != 0 and 10 / x > 1)\nprint(x == 0 or 10 / x > 1)\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`False` puis une erreur `ZeroDivisionError`",
          "correct": false,
          "feedback": "Erreur : `or` est lui aussi séquentiel. Son opérande gauche,\n`x == 0`, est vrai : le résultat vaut `True` et la division\n`10 / x` n'est jamais calculée.\n"
        },
        {
          "text": "`True` puis `False`",
          "correct": false,
          "feedback": "Erreur : les deux résultats sont inversés. `x != 0` est faux pour\n`x` nul, donc le `and` vaut `False` ; `x == 0` est vrai, donc le\n`or` vaut `True`.\n"
        },
        {
          "text": "Une erreur `ZeroDivisionError` dès le premier `print`",
          "correct": false,
          "feedback": "Erreur : `and` n'évalue pas son opérande droit quand l'opérande\ngauche est faux. Comme `x != 0` vaut `False`, la division par zéro\nn'a jamais lieu.\n"
        },
        {
          "text": "`False` puis `True`",
          "correct": true,
          "feedback": "Bonne réponse : `and` et `or` évaluent leurs opérandes de gauche à\ndroite et s'arrêtent dès que le résultat est connu. `x != 0` est\nfaux, donc le `and` vaut `False` sans calculer `10 / x` ; `x == 0`\nest vrai, donc le `or` vaut `True` sans calculer `10 / x`.\n"
        }
      ],
      "explanation": "Le caractère séquentiel de `and` et `or` permet de protéger une\nopération risquée : dans `x != 0 and 10 / x > 1`, la division n'est\ntentée que si `x` est non nul."
    },
    {
      "id": "q30",
      "difficulty": 1,
      "skills": [
        "concatenation",
        "type-str"
      ],
      "title": "Addition de deux chaînes",
      "partie": "chaines",
      "statement": "Que vaut l'expression `\"3\" + \"4\"` en Python ?",
      "options": [
        {
          "text": "`'34'`",
          "correct": true,
          "feedback": "Bonne réponse : entre deux chaînes, `+` est la concaténation.\nLes caractères de `\"4\"` sont ajoutés à la suite de ceux de\n`\"3\"`, sans aucun calcul.\n"
        },
        {
          "text": "`7`",
          "correct": false,
          "feedback": "Erreur : les guillemets font de `\"3\"` et `\"4\"` des chaînes,\npas des nombres. Pour obtenir `7`, il faudrait convertir les\ndeux avec `int` avant d'additionner.\n"
        },
        {
          "text": "`'7'`",
          "correct": false,
          "feedback": "Erreur : Python n'additionne pas le contenu des chaînes. Il les\nmet bout à bout, ce qui donne `'34'`.\n"
        },
        {
          "text": "Une erreur, car `+` ne s'applique pas aux chaînes",
          "correct": false,
          "feedback": "Erreur : `+` s'applique bien à deux chaînes et les concatène.\nL'erreur n'apparaît que si l'on mélange une chaîne et un nombre.\n"
        }
      ],
      "explanation": "Le même symbole `+` additionne deux nombres et concatène deux\nchaînes. C'est le type des opérandes qui décide : `\"3\" + \"4\"`\nvaut `'34'`, alors que `3 + 4` vaut `7`.",
      "variants": [
        {
          "statement": "Que vaut l'expression `\"3\" + \"4\"` en Python ?",
          "options": [
            {
              "text": "`'34'`",
              "correct": true,
              "feedback": "Bonne réponse : entre deux chaînes, `+` est la concaténation.\nLes caractères de `\"4\"` sont ajoutés à la suite de ceux de\n`\"3\"`, sans aucun calcul.\n"
            },
            {
              "text": "`7`",
              "correct": false,
              "feedback": "Erreur : les guillemets font de `\"3\"` et `\"4\"` des chaînes,\npas des nombres. Pour obtenir `7`, il faudrait convertir les\ndeux avec `int` avant d'additionner.\n"
            },
            {
              "text": "`'7'`",
              "correct": false,
              "feedback": "Erreur : Python n'additionne pas le contenu des chaînes. Il les\nmet bout à bout, ce qui donne `'34'`.\n"
            },
            {
              "text": "Une erreur, car `+` ne s'applique pas aux chaînes",
              "correct": false,
              "feedback": "Erreur : `+` s'applique bien à deux chaînes et les concatène.\nL'erreur n'apparaît que si l'on mélange une chaîne et un nombre.\n"
            }
          ],
          "explanation": "Le même symbole `+` additionne deux nombres et concatène deux\nchaînes. C'est le type des opérandes qui décide : `\"3\" + \"4\"`\nvaut `'34'`, alors que `3 + 4` vaut `7`."
        },
        {
          "statement": "Que vaut l'expression `\"12\" + \"5\"` en Python ?",
          "options": [
            {
              "text": "`'125'`",
              "correct": true,
              "feedback": "Bonne réponse : entre deux chaînes, `+` est la concaténation.\nLes caractères de `\"5\"` sont ajoutés à la suite de ceux de\n`\"12\"`, sans aucun calcul.\n"
            },
            {
              "text": "`17`",
              "correct": false,
              "feedback": "Erreur : les guillemets font de `\"12\"` et `\"5\"` des chaînes,\npas des nombres. Pour obtenir `17`, il faudrait convertir les\ndeux avec `int` avant d'additionner.\n"
            },
            {
              "text": "`'17'`",
              "correct": false,
              "feedback": "Erreur : Python n'additionne pas le contenu des chaînes. Il les\nmet bout à bout, ce qui donne `'125'`.\n"
            },
            {
              "text": "Une erreur, car `+` ne s'applique pas aux chaînes",
              "correct": false,
              "feedback": "Erreur : `+` s'applique bien à deux chaînes et les concatène.\nL'erreur n'apparaît que si l'on mélange une chaîne et un nombre.\n"
            }
          ],
          "explanation": "Le même symbole `+` additionne deux nombres et concatène deux\nchaînes. C'est le type des opérandes qui décide : `\"12\" + \"5\"`\nvaut `'125'`, alors que `12 + 5` vaut `17`."
        },
        {
          "statement": "Que vaut l'expression `\"7\" + \"70\"` en Python ?",
          "options": [
            {
              "text": "`'770'`",
              "correct": true,
              "feedback": "Bonne réponse : entre deux chaînes, `+` est la concaténation.\nLes caractères de `\"70\"` sont ajoutés à la suite de ceux de\n`\"7\"`, sans aucun calcul.\n"
            },
            {
              "text": "`77`",
              "correct": false,
              "feedback": "Erreur : les guillemets font de `\"7\"` et `\"70\"` des chaînes,\npas des nombres. Pour obtenir `77`, il faudrait convertir les\ndeux avec `int` avant d'additionner.\n"
            },
            {
              "text": "`'77'`",
              "correct": false,
              "feedback": "Erreur : Python n'additionne pas le contenu des chaînes. Il les\nmet bout à bout, ce qui donne `'770'`.\n"
            },
            {
              "text": "Une erreur, car `+` ne s'applique pas aux chaînes",
              "correct": false,
              "feedback": "Erreur : `+` s'applique bien à deux chaînes et les concatène.\nL'erreur n'apparaît que si l'on mélange une chaîne et un nombre.\n"
            }
          ],
          "explanation": "Le même symbole `+` additionne deux nombres et concatène deux\nchaînes. C'est le type des opérandes qui décide : `\"7\" + \"70\"`\nvaut `'770'`, alors que `7 + 70` vaut `77`."
        }
      ]
    },
    {
      "id": "q31",
      "difficulty": 2,
      "skills": [
        "repetition",
        "type-str",
        "operateur"
      ],
      "title": "Multiplication d'une chaîne par un entier",
      "partie": "chaines",
      "statement": "Que vaut l'expression `\"ab\" * 3` en Python ?",
      "options": [
        {
          "text": "`'ababab'`",
          "correct": true,
          "feedback": "Bonne réponse : multiplier une chaîne par un entier la répète.\n`\"ab\"` est recopiée trois fois à la suite, sans séparateur.\n"
        },
        {
          "text": "`'ab ab ab'`",
          "correct": false,
          "feedback": "Erreur : la répétition n'insère aucun espace. Les copies sont\ncollées les unes aux autres : `'ababab'`.\n"
        },
        {
          "text": "`'ab3'`",
          "correct": false,
          "feedback": "Erreur : `*` ne colle pas le nombre à la chaîne. Il répète la\nchaîne, ce qui donne `'ababab'`.\n"
        },
        {
          "text": "Une erreur, car on ne multiplie pas une chaîne par un entier",
          "correct": false,
          "feedback": "Erreur : cette opération est permise et très utilisée, par\nexemple `\"-\" * 20` pour tracer une ligne. Seule la\nmultiplication de deux chaînes entre elles est interdite.\n"
        }
      ],
      "explanation": "Avec une chaîne et un entier, `*` répète la chaîne. Avec deux\nchaînes, l'opération n'a pas de sens et lève une erreur.",
      "variants": [
        {
          "statement": "Que vaut l'expression `\"ab\" * 3` en Python ?",
          "options": [
            {
              "text": "`'ababab'`",
              "correct": true,
              "feedback": "Bonne réponse : multiplier une chaîne par un entier la répète.\n`\"ab\"` est recopiée trois fois à la suite, sans séparateur.\n"
            },
            {
              "text": "`'ab ab ab'`",
              "correct": false,
              "feedback": "Erreur : la répétition n'insère aucun espace. Les copies sont\ncollées les unes aux autres : `'ababab'`.\n"
            },
            {
              "text": "`'ab3'`",
              "correct": false,
              "feedback": "Erreur : `*` ne colle pas le nombre à la chaîne. Il répète la\nchaîne, ce qui donne `'ababab'`.\n"
            },
            {
              "text": "Une erreur, car on ne multiplie pas une chaîne par un entier",
              "correct": false,
              "feedback": "Erreur : cette opération est permise et très utilisée, par\nexemple `\"-\" * 20` pour tracer une ligne. Seule la\nmultiplication de deux chaînes entre elles est interdite.\n"
            }
          ],
          "explanation": "Avec une chaîne et un entier, `*` répète la chaîne. Avec deux\nchaînes, l'opération n'a pas de sens et lève une erreur."
        },
        {
          "statement": "Que vaut l'expression `\"no\" * 2` en Python ?",
          "options": [
            {
              "text": "`'nono'`",
              "correct": true,
              "feedback": "Bonne réponse : multiplier une chaîne par un entier la répète.\n`\"no\"` est recopiée deux fois à la suite, sans séparateur.\n"
            },
            {
              "text": "`'no no'`",
              "correct": false,
              "feedback": "Erreur : la répétition n'insère aucun espace. Les copies sont\ncollées les unes aux autres : `'nono'`.\n"
            },
            {
              "text": "`'no2'`",
              "correct": false,
              "feedback": "Erreur : `*` ne colle pas le nombre à la chaîne. Il répète la\nchaîne, ce qui donne `'nono'`.\n"
            },
            {
              "text": "Une erreur, car on ne multiplie pas une chaîne par un entier",
              "correct": false,
              "feedback": "Erreur : cette opération est permise et très utilisée, par\nexemple `\"-\" * 20` pour tracer une ligne. Seule la\nmultiplication de deux chaînes entre elles est interdite.\n"
            }
          ],
          "explanation": "Avec une chaîne et un entier, `*` répète la chaîne. Avec deux\nchaînes, l'opération n'a pas de sens et lève une erreur."
        },
        {
          "statement": "Que vaut l'expression `\"x\" * 4` en Python ?",
          "options": [
            {
              "text": "`'xxxx'`",
              "correct": true,
              "feedback": "Bonne réponse : multiplier une chaîne par un entier la répète.\n`\"x\"` est recopiée quatre fois à la suite, sans séparateur.\n"
            },
            {
              "text": "`'x x x x'`",
              "correct": false,
              "feedback": "Erreur : la répétition n'insère aucun espace. Les copies sont\ncollées les unes aux autres : `'xxxx'`.\n"
            },
            {
              "text": "`'x4'`",
              "correct": false,
              "feedback": "Erreur : `*` ne colle pas le nombre à la chaîne. Il répète la\nchaîne, ce qui donne `'xxxx'`.\n"
            },
            {
              "text": "Une erreur, car on ne multiplie pas une chaîne par un entier",
              "correct": false,
              "feedback": "Erreur : cette opération est permise et très utilisée, par\nexemple `\"-\" * 20` pour tracer une ligne. Seule la\nmultiplication de deux chaînes entre elles est interdite.\n"
            }
          ],
          "explanation": "Avec une chaîne et un entier, `*` répète la chaîne. Avec deux\nchaînes, l'opération n'a pas de sens et lève une erreur."
        }
      ]
    },
    {
      "id": "q32",
      "difficulty": 2,
      "skills": [
        "indexation",
        "len",
        "type-str"
      ],
      "title": "Dernier caractère d'une chaîne",
      "partie": "chaines",
      "statement": "Qu'affiche ce programme ?\n```python\nmot = \"python\"\nprint(mot[len(mot) - 1])\n```",
      "options": [
        {
          "text": "`n`",
          "correct": true,
          "feedback": "Bonne réponse : `len(mot)` vaut 6 et les indices vont de `0`\nà 5. L'indice `len(mot) - 1`, soit 5, désigne donc le\ndernier caractère, `n`.\n"
        },
        {
          "text": "`p`",
          "correct": false,
          "feedback": "Erreur : le premier caractère est à l'indice `0`. L'indice\n`len(mot) - 1` vaut 5 et désigne le dernier caractère.\n"
        },
        {
          "text": "`o`",
          "correct": false,
          "feedback": "Erreur : l'avant-dernier caractère est à l'indice\n`len(mot) - 2`, soit 4. À l'indice 5 se trouve `n`.\n"
        },
        {
          "text": "Une erreur, car l'indice dépasse la longueur de la chaîne",
          "correct": false,
          "feedback": "Erreur : c'est `mot[len(mot)]`, d'indice 6, qui serait hors\nlimites. En retranchant `1`, on tombe exactement sur le dernier\nindice valide.\n"
        }
      ],
      "explanation": "Les indices d'une chaîne de longueur $n$ vont de $0$ à $n - 1$. Le\ndernier caractère s'obtient donc avec `mot[len(mot) - 1]`.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\nmot = \"python\"\nprint(mot[len(mot) - 1])\n```",
          "options": [
            {
              "text": "`n`",
              "correct": true,
              "feedback": "Bonne réponse : `len(mot)` vaut 6 et les indices vont de `0`\nà 5. L'indice `len(mot) - 1`, soit 5, désigne donc le\ndernier caractère, `n`.\n"
            },
            {
              "text": "`p`",
              "correct": false,
              "feedback": "Erreur : le premier caractère est à l'indice `0`. L'indice\n`len(mot) - 1` vaut 5 et désigne le dernier caractère.\n"
            },
            {
              "text": "`o`",
              "correct": false,
              "feedback": "Erreur : l'avant-dernier caractère est à l'indice\n`len(mot) - 2`, soit 4. À l'indice 5 se trouve `n`.\n"
            },
            {
              "text": "Une erreur, car l'indice dépasse la longueur de la chaîne",
              "correct": false,
              "feedback": "Erreur : c'est `mot[len(mot)]`, d'indice 6, qui serait hors\nlimites. En retranchant `1`, on tombe exactement sur le dernier\nindice valide.\n"
            }
          ],
          "explanation": "Les indices d'une chaîne de longueur $n$ vont de $0$ à $n - 1$. Le\ndernier caractère s'obtient donc avec `mot[len(mot) - 1]`."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nmot = \"nsi\"\nprint(mot[len(mot) - 1])\n```",
          "options": [
            {
              "text": "`i`",
              "correct": true,
              "feedback": "Bonne réponse : `len(mot)` vaut 3 et les indices vont de `0`\nà 2. L'indice `len(mot) - 1`, soit 2, désigne donc le\ndernier caractère, `i`.\n"
            },
            {
              "text": "`n`",
              "correct": false,
              "feedback": "Erreur : le premier caractère est à l'indice `0`. L'indice\n`len(mot) - 1` vaut 2 et désigne le dernier caractère.\n"
            },
            {
              "text": "`s`",
              "correct": false,
              "feedback": "Erreur : l'avant-dernier caractère est à l'indice\n`len(mot) - 2`, soit 1. À l'indice 2 se trouve `i`.\n"
            },
            {
              "text": "Une erreur, car l'indice dépasse la longueur de la chaîne",
              "correct": false,
              "feedback": "Erreur : c'est `mot[len(mot)]`, d'indice 3, qui serait hors\nlimites. En retranchant `1`, on tombe exactement sur le dernier\nindice valide.\n"
            }
          ],
          "explanation": "Les indices d'une chaîne de longueur $n$ vont de $0$ à $n - 1$. Le\ndernier caractère s'obtient donc avec `mot[len(mot) - 1]`."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nmot = \"info\"\nprint(mot[len(mot) - 1])\n```",
          "options": [
            {
              "text": "`o`",
              "correct": true,
              "feedback": "Bonne réponse : `len(mot)` vaut 4 et les indices vont de `0`\nà 3. L'indice `len(mot) - 1`, soit 3, désigne donc le\ndernier caractère, `o`.\n"
            },
            {
              "text": "`i`",
              "correct": false,
              "feedback": "Erreur : le premier caractère est à l'indice `0`. L'indice\n`len(mot) - 1` vaut 3 et désigne le dernier caractère.\n"
            },
            {
              "text": "`f`",
              "correct": false,
              "feedback": "Erreur : l'avant-dernier caractère est à l'indice\n`len(mot) - 2`, soit 2. À l'indice 3 se trouve `o`.\n"
            },
            {
              "text": "Une erreur, car l'indice dépasse la longueur de la chaîne",
              "correct": false,
              "feedback": "Erreur : c'est `mot[len(mot)]`, d'indice 4, qui serait hors\nlimites. En retranchant `1`, on tombe exactement sur le dernier\nindice valide.\n"
            }
          ],
          "explanation": "Les indices d'une chaîne de longueur $n$ vont de $0$ à $n - 1$. Le\ndernier caractère s'obtient donc avec `mot[len(mot) - 1]`."
        }
      ]
    },
    {
      "id": "q33",
      "difficulty": 2,
      "skills": [
        "nom-de-variable",
        "mot-cle"
      ],
      "title": "Un nom de variable interdit",
      "partie": "variables",
      "statement": "Que produit l'instruction `class = 3` ?",
      "options": [
        {
          "text": "Une erreur de syntaxe, `class` étant un mot réservé",
          "correct": true,
          "feedback": "Bonne réponse : les mots-clés comme `class`, `if`, `for` ou\n`def` sont réservés et ne peuvent pas servir de nom de variable.\n"
        },
        {
          "text": "La création d'une variable `class` valant $3$",
          "correct": false,
          "feedback": "Erreur : Python refuse ce nom avant même d'exécuter\nl'affectation.\n"
        },
        {
          "text": "Un avertissement, puis la création de la variable",
          "correct": false,
          "feedback": "Erreur : il ne s'agit pas d'un avertissement mais d'une erreur\nbloquante.\n"
        },
        {
          "text": "La création d'une classe nommée `3`, sans attribut",
          "correct": false,
          "feedback": "Erreur : définir une classe demande une autre syntaxe, et `3`\nn'est pas un nom valide.\n"
        }
      ],
      "explanation": "Un nom de variable commence par une lettre ou un tiret bas, ne\ncontient ni espace ni accent de préférence, et n'est jamais un\nmot-clé. `classe` ou `niveau` conviennent."
    },
    {
      "id": "q34",
      "difficulty": 2,
      "skills": [
        "affectation-raccourcie",
        "trace"
      ],
      "title": "Trois affectations raccourcies",
      "partie": "variables",
      "statement": "Qu'affiche ce programme ?\n```python\nn = 10\nn -= 4\nn *= 2\nprint(n)\n```",
      "options": [
        {
          "text": "`12`",
          "correct": true,
          "feedback": "Bonne réponse : `n -= 4` retire 4, puis `n *= 2` multiplie\nle résultat par 2 : $(10 - 4) \\times 2 = 12$.\n"
        },
        {
          "text": "`2`",
          "correct": false,
          "feedback": "Erreur : les deux instructions s'enchaînent ; la multiplication\nporte sur la valeur déjà diminuée.\n"
        },
        {
          "text": "`10`",
          "correct": false,
          "feedback": "Erreur : chaque écriture raccourcie modifie bien `n`.\n"
        },
        {
          "text": "Une erreur, `-=` n'existant pas en Python",
          "correct": false,
          "feedback": "Erreur : `n -= 4` est l'abréviation de `n = n - 4`.\n"
        }
      ],
      "explanation": "`n -= a` et `n *= b` abrègent `n = n - a` et `n = n * b` ; chaque\ninstruction part de la valeur courante.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\nn = 10\nn -= 4\nn *= 2\nprint(n)\n```",
          "options": [
            {
              "text": "`12`",
              "correct": true,
              "feedback": "Bonne réponse : `n -= 4` retire 4, puis `n *= 2` multiplie\nle résultat par 2 : $(10 - 4) \\times 2 = 12$.\n"
            },
            {
              "text": "`2`",
              "correct": false,
              "feedback": "Erreur : les deux instructions s'enchaînent ; la multiplication\nporte sur la valeur déjà diminuée.\n"
            },
            {
              "text": "`10`",
              "correct": false,
              "feedback": "Erreur : chaque écriture raccourcie modifie bien `n`.\n"
            },
            {
              "text": "Une erreur, `-=` n'existant pas en Python",
              "correct": false,
              "feedback": "Erreur : `n -= 4` est l'abréviation de `n = n - 4`.\n"
            }
          ],
          "explanation": "`n -= a` et `n *= b` abrègent `n = n - a` et `n = n * b` ; chaque\ninstruction part de la valeur courante."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nn = 7\nn -= 3\nn *= 5\nprint(n)\n```",
          "options": [
            {
              "text": "`20`",
              "correct": true,
              "feedback": "Bonne réponse : `n -= 3` retire 3, puis `n *= 5` multiplie\nle résultat par 5 : $(7 - 3) \\times 5 = 20$.\n"
            },
            {
              "text": "`-8`",
              "correct": false,
              "feedback": "Erreur : les deux instructions s'enchaînent ; la multiplication\nporte sur la valeur déjà diminuée.\n"
            },
            {
              "text": "`7`",
              "correct": false,
              "feedback": "Erreur : chaque écriture raccourcie modifie bien `n`.\n"
            },
            {
              "text": "Une erreur, `-=` n'existant pas en Python",
              "correct": false,
              "feedback": "Erreur : `n -= 3` est l'abréviation de `n = n - 3`.\n"
            }
          ],
          "explanation": "`n -= a` et `n *= b` abrègent `n = n - a` et `n = n * b` ; chaque\ninstruction part de la valeur courante."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nn = 20\nn -= 8\nn *= 3\nprint(n)\n```",
          "options": [
            {
              "text": "`36`",
              "correct": true,
              "feedback": "Bonne réponse : `n -= 8` retire 8, puis `n *= 3` multiplie\nle résultat par 3 : $(20 - 8) \\times 3 = 36$.\n"
            },
            {
              "text": "`-4`",
              "correct": false,
              "feedback": "Erreur : les deux instructions s'enchaînent ; la multiplication\nporte sur la valeur déjà diminuée.\n"
            },
            {
              "text": "`20`",
              "correct": false,
              "feedback": "Erreur : chaque écriture raccourcie modifie bien `n`.\n"
            },
            {
              "text": "Une erreur, `-=` n'existant pas en Python",
              "correct": false,
              "feedback": "Erreur : `n -= 8` est l'abréviation de `n = n - 8`.\n"
            }
          ],
          "explanation": "`n -= a` et `n *= b` abrègent `n = n - a` et `n = n * b` ; chaque\ninstruction part de la valeur courante."
        }
      ]
    },
    {
      "id": "q35",
      "difficulty": 2,
      "skills": [
        "priorite",
        "puissance",
        "signe"
      ],
      "title": "Un signe moins devant une puissance",
      "partie": "operations",
      "statement": "Que vaut `-2 ** 2` en Python ?",
      "options": [
        {
          "text": "`-4`",
          "correct": true,
          "feedback": "Bonne réponse : `**` est prioritaire sur le signe moins.\nL'expression se lit `-(2 ** 2)`, soit -4.\n"
        },
        {
          "text": "`4`",
          "correct": false,
          "feedback": "Erreur : ce serait `(-2) ** 2`. Sans parenthèses, le signe\ns'applique après la puissance.\n"
        },
        {
          "text": "`-2`",
          "correct": false,
          "feedback": "Erreur : la puissance est bien calculée.\n"
        },
        {
          "text": "Une erreur de syntaxe",
          "correct": false,
          "feedback": "Erreur : l'expression est valide, seule sa lecture demande de\nconnaître les priorités.\n"
        }
      ],
      "explanation": "`**` passe avant le signe et avant `*` ; en cas de doute, on écrit\n`(-2) ** 2` ou `-(2 ** 2)` pour lever l'ambiguïté.",
      "variants": [
        {
          "statement": "Que vaut `-2 ** 2` en Python ?",
          "options": [
            {
              "text": "`-4`",
              "correct": true,
              "feedback": "Bonne réponse : `**` est prioritaire sur le signe moins.\nL'expression se lit `-(2 ** 2)`, soit -4.\n"
            },
            {
              "text": "`4`",
              "correct": false,
              "feedback": "Erreur : ce serait `(-2) ** 2`. Sans parenthèses, le signe\ns'applique après la puissance.\n"
            },
            {
              "text": "`-2`",
              "correct": false,
              "feedback": "Erreur : la puissance est bien calculée.\n"
            },
            {
              "text": "Une erreur de syntaxe",
              "correct": false,
              "feedback": "Erreur : l'expression est valide, seule sa lecture demande de\nconnaître les priorités.\n"
            }
          ],
          "explanation": "`**` passe avant le signe et avant `*` ; en cas de doute, on écrit\n`(-2) ** 2` ou `-(2 ** 2)` pour lever l'ambiguïté."
        },
        {
          "statement": "Que vaut `-3 ** 2` en Python ?",
          "options": [
            {
              "text": "`-9`",
              "correct": true,
              "feedback": "Bonne réponse : `**` est prioritaire sur le signe moins.\nL'expression se lit `-(3 ** 2)`, soit -9.\n"
            },
            {
              "text": "`9`",
              "correct": false,
              "feedback": "Erreur : ce serait `(-3) ** 2`. Sans parenthèses, le signe\ns'applique après la puissance.\n"
            },
            {
              "text": "`-3`",
              "correct": false,
              "feedback": "Erreur : la puissance est bien calculée.\n"
            },
            {
              "text": "Une erreur de syntaxe",
              "correct": false,
              "feedback": "Erreur : l'expression est valide, seule sa lecture demande de\nconnaître les priorités.\n"
            }
          ],
          "explanation": "`**` passe avant le signe et avant `*` ; en cas de doute, on écrit\n`(-3) ** 2` ou `-(3 ** 2)` pour lever l'ambiguïté."
        },
        {
          "statement": "Que vaut `-5 ** 2` en Python ?",
          "options": [
            {
              "text": "`-25`",
              "correct": true,
              "feedback": "Bonne réponse : `**` est prioritaire sur le signe moins.\nL'expression se lit `-(5 ** 2)`, soit -25.\n"
            },
            {
              "text": "`25`",
              "correct": false,
              "feedback": "Erreur : ce serait `(-5) ** 2`. Sans parenthèses, le signe\ns'applique après la puissance.\n"
            },
            {
              "text": "`-5`",
              "correct": false,
              "feedback": "Erreur : la puissance est bien calculée.\n"
            },
            {
              "text": "Une erreur de syntaxe",
              "correct": false,
              "feedback": "Erreur : l'expression est valide, seule sa lecture demande de\nconnaître les priorités.\n"
            }
          ],
          "explanation": "`**` passe avant le signe et avant `*` ; en cas de doute, on écrit\n`(-5) ** 2` ou `-(5 ** 2)` pour lever l'ambiguïté."
        }
      ]
    },
    {
      "id": "q36",
      "difficulty": 3,
      "skills": [
        "modulo",
        "negatif",
        "division-entiere"
      ],
      "title": "Le reste d'un nombre négatif",
      "partie": "operations",
      "statement": "Que vaut `-7 % 3` en Python ?",
      "options": [
        {
          "text": "`2`",
          "correct": true,
          "feedback": "Bonne réponse : en Python, le reste a le signe du diviseur et\nvérifie `-7 == 3 * (-7 // 3) + 2`, avec `-7 // 3`\nvalant -3.\n"
        },
        {
          "text": "`-1`",
          "correct": false,
          "feedback": "Erreur : -1 est le reste au sens de certains autres langages,\nqui gardent le signe du dividende. Python arrondit la division\nentière vers le bas, ce qui donne un reste positif.\n"
        },
        {
          "text": "`1`",
          "correct": false,
          "feedback": "Erreur : 1 serait le reste de la valeur absolue ; le signe\ndu dividende change le résultat.\n"
        },
        {
          "text": "Une erreur, le modulo n'acceptant pas un nombre négatif",
          "correct": false,
          "feedback": "Erreur : `%` accepte tous les entiers.\n"
        }
      ],
      "explanation": "Python garantit `a == b * (a // b) + a % b` avec un reste compris\nentre $0$ et $b - 1$ pour `b` positif, même quand `a` est négatif.",
      "variants": [
        {
          "statement": "Que vaut `-7 % 3` en Python ?",
          "options": [
            {
              "text": "`2`",
              "correct": true,
              "feedback": "Bonne réponse : en Python, le reste a le signe du diviseur et\nvérifie `-7 == 3 * (-7 // 3) + 2`, avec `-7 // 3`\nvalant -3.\n"
            },
            {
              "text": "`-1`",
              "correct": false,
              "feedback": "Erreur : -1 est le reste au sens de certains autres langages,\nqui gardent le signe du dividende. Python arrondit la division\nentière vers le bas, ce qui donne un reste positif.\n"
            },
            {
              "text": "`1`",
              "correct": false,
              "feedback": "Erreur : 1 serait le reste de la valeur absolue ; le signe\ndu dividende change le résultat.\n"
            },
            {
              "text": "Une erreur, le modulo n'acceptant pas un nombre négatif",
              "correct": false,
              "feedback": "Erreur : `%` accepte tous les entiers.\n"
            }
          ],
          "explanation": "Python garantit `a == b * (a // b) + a % b` avec un reste compris\nentre $0$ et $b - 1$ pour `b` positif, même quand `a` est négatif."
        },
        {
          "statement": "Que vaut `-9 % 4` en Python ?",
          "options": [
            {
              "text": "`3`",
              "correct": true,
              "feedback": "Bonne réponse : en Python, le reste a le signe du diviseur et\nvérifie `-9 == 4 * (-9 // 4) + 3`, avec `-9 // 4`\nvalant -3.\n"
            },
            {
              "text": "`-1`",
              "correct": false,
              "feedback": "Erreur : -1 est le reste au sens de certains autres langages,\nqui gardent le signe du dividende. Python arrondit la division\nentière vers le bas, ce qui donne un reste positif.\n"
            },
            {
              "text": "`1`",
              "correct": false,
              "feedback": "Erreur : 1 serait le reste de la valeur absolue ; le signe\ndu dividende change le résultat.\n"
            },
            {
              "text": "Une erreur, le modulo n'acceptant pas un nombre négatif",
              "correct": false,
              "feedback": "Erreur : `%` accepte tous les entiers.\n"
            }
          ],
          "explanation": "Python garantit `a == b * (a // b) + a % b` avec un reste compris\nentre $0$ et $b - 1$ pour `b` positif, même quand `a` est négatif."
        },
        {
          "statement": "Que vaut `-5 % 6` en Python ?",
          "options": [
            {
              "text": "`1`",
              "correct": true,
              "feedback": "Bonne réponse : en Python, le reste a le signe du diviseur et\nvérifie `-5 == 6 * (-5 // 6) + 1`, avec `-5 // 6`\nvalant -1.\n"
            },
            {
              "text": "`-5`",
              "correct": false,
              "feedback": "Erreur : -5 est le reste au sens de certains autres langages,\nqui gardent le signe du dividende. Python arrondit la division\nentière vers le bas, ce qui donne un reste positif.\n"
            },
            {
              "text": "`5`",
              "correct": false,
              "feedback": "Erreur : 5 serait le reste de la valeur absolue ; le signe\ndu dividende change le résultat.\n"
            },
            {
              "text": "Une erreur, le modulo n'acceptant pas un nombre négatif",
              "correct": false,
              "feedback": "Erreur : `%` accepte tous les entiers.\n"
            }
          ],
          "explanation": "Python garantit `a == b * (a // b) + a % b` avec un reste compris\nentre $0$ et $b - 1$ pour `b` positif, même quand `a` est négatif."
        }
      ]
    },
    {
      "id": "q37",
      "difficulty": 2,
      "skills": [
        "chaines",
        "immuabilite",
        "erreur"
      ],
      "title": "Modifier un caractère d'une chaîne",
      "partie": "chaines",
      "statement": "Que produit ce programme ?\n```python\ns = \"bonjour\"\ns[0] = \"B\"\n```",
      "options": [
        {
          "text": "Une erreur, les chaînes étant immuables",
          "correct": true,
          "feedback": "Bonne réponse : les chaînes sont immuables ; pour obtenir\n`Bonjour`, on construit une nouvelle chaîne, par exemple\n`\"B\" + s[1:]`.\n"
        },
        {
          "text": "`s` devient `Bonjour`, le premier caractère remplacé",
          "correct": false,
          "feedback": "Erreur : l'affectation par indice est refusée sur une chaîne.\n"
        },
        {
          "text": "`s` devient `B`, l'affectation écrasant le reste",
          "correct": false,
          "feedback": "Erreur : il n'y a ni remplacement ni raccourcissement, mais\nune erreur.\n"
        },
        {
          "text": "Rien, la modification étant ignorée en silence",
          "correct": false,
          "feedback": "Erreur : Python signale l'opération interdite par une\nexception.\n"
        }
      ],
      "explanation": "Une chaîne ne change jamais : toute « modification » crée une\nnouvelle chaîne, ce que font `upper`, `replace` ou la\nconcaténation."
    },
    {
      "id": "q38",
      "difficulty": 2,
      "skills": [
        "chaines",
        "in",
        "sous-chaine"
      ],
      "title": "Tester la présence d'une sous-chaîne",
      "partie": "chaines",
      "statement": "Que vaut l'expression `\"jour\" in \"bonjour\"` ?",
      "options": [
        {
          "text": "`True`, `jour` figure d'un seul tenant dans `bonjour`",
          "correct": true,
          "feedback": "Bonne réponse : `in` teste si la chaîne de gauche apparaît\ntelle quelle, caractères consécutifs, dans celle de droite.\n"
        },
        {
          "text": "`False`, `in` ne cherchant qu'un caractère isolé",
          "correct": false,
          "feedback": "Erreur : `in` cherche la sous-chaîne entière, consécutive, pas\nses lettres une à une.\n"
        },
        {
          "text": "Une erreur, `in` ne s'appliquant qu'aux listes",
          "correct": false,
          "feedback": "Erreur : `in` fonctionne aussi sur les chaînes.\n"
        },
        {
          "text": "Un entier, la position de `jour` dans `bonjour`",
          "correct": false,
          "feedback": "Erreur : `in` renvoie un booléen ; la position s'obtient par\n`find`.\n"
        }
      ],
      "explanation": "`sous in chaine` répond vrai si `sous` apparaît d'un seul tenant\ndans `chaine`, sans dire où.",
      "variants": [
        {
          "statement": "Que vaut l'expression `\"jour\" in \"bonjour\"` ?",
          "options": [
            {
              "text": "`True`, `jour` figure d'un seul tenant dans `bonjour`",
              "correct": true,
              "feedback": "Bonne réponse : `in` teste si la chaîne de gauche apparaît\ntelle quelle, caractères consécutifs, dans celle de droite.\n"
            },
            {
              "text": "`False`, `in` ne cherchant qu'un caractère isolé",
              "correct": false,
              "feedback": "Erreur : `in` cherche la sous-chaîne entière, consécutive, pas\nses lettres une à une.\n"
            },
            {
              "text": "Une erreur, `in` ne s'appliquant qu'aux listes",
              "correct": false,
              "feedback": "Erreur : `in` fonctionne aussi sur les chaînes.\n"
            },
            {
              "text": "Un entier, la position de `jour` dans `bonjour`",
              "correct": false,
              "feedback": "Erreur : `in` renvoie un booléen ; la position s'obtient par\n`find`.\n"
            }
          ],
          "explanation": "`sous in chaine` répond vrai si `sous` apparaît d'un seul tenant\ndans `chaine`, sans dire où."
        },
        {
          "statement": "Que vaut l'expression `\"bjr\" in \"bonjour\"` ?",
          "options": [
            {
              "text": "`False`, les lettres de `bjr` ne se suivent pas dans `bonjour`",
              "correct": true,
              "feedback": "Bonne réponse : `in` teste si la chaîne de gauche apparaît\ntelle quelle, caractères consécutifs, dans celle de droite.\n"
            },
            {
              "text": "`True`, chaque lettre de `bjr` figurant dans `bonjour`",
              "correct": false,
              "feedback": "Erreur : `in` cherche la sous-chaîne entière, consécutive, pas\nses lettres une à une.\n"
            },
            {
              "text": "Une erreur, `in` ne s'appliquant qu'aux listes",
              "correct": false,
              "feedback": "Erreur : `in` fonctionne aussi sur les chaînes.\n"
            },
            {
              "text": "Un entier, la position de `bjr` dans `bonjour`",
              "correct": false,
              "feedback": "Erreur : `in` renvoie un booléen ; la position s'obtient par\n`find`.\n"
            }
          ],
          "explanation": "`sous in chaine` répond vrai si `sous` apparaît d'un seul tenant\ndans `chaine`, sans dire où."
        }
      ]
    }
  ]
}