{
  "chapter": {
    "id": "fonctions",
    "level": "premiere",
    "theme": "Programmation",
    "title": "Fonctions",
    "description": "Définition de fonctions en Python, paramètres et valeur\nde retour, portée locale et globale, fonctions natives,\nfonctions sans retour, paramètres par défaut, documentation\n(docstrings).",
    "parties": [
      {
        "id": "definition",
        "title": "Définir, appeler, documenter"
      },
      {
        "id": "parametres",
        "title": "Paramètres et valeurs de retour"
      },
      {
        "id": "portee",
        "title": "Portée des variables et effets de bord"
      }
    ],
    "prerequisites": [],
    "references": []
  },
  "questions": [
    {
      "id": "q01",
      "difficulty": 1,
      "skills": [
        "definition"
      ],
      "title": "Définir une fonction",
      "partie": "definition",
      "statement": "Comment définit-on une fonction `carre` qui\nprend `x` en paramètre et renvoie `x * x` ?",
      "options": [
        {
          "text": "```python\ndef carre(x) -> x * x\n```\n",
          "correct": false,
          "feedback": "Erreur : `->` indique le type de retour\n(annotation), pas l'expression. Il manque\nle corps de la fonction.\n"
        },
        {
          "text": "```python\ncarre = x * x\n```\n",
          "correct": false,
          "feedback": "Erreur : on définirait une variable, pas\nune fonction.\n"
        },
        {
          "text": "```python\nfunction carre(x) {\n    return x * x\n}\n```\n",
          "correct": false,
          "feedback": "Erreur : syntaxe JavaScript, pas Python.\n"
        },
        {
          "text": "```python\ndef carre(x):\n    return x * x\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : mot-clé `def`, parenthèses,\ndeux-points, indentation, `return`.\n"
        }
      ],
      "explanation": "Syntaxe canonique : `def nom(params): corps`.\nLe mot-clé `return` produit la valeur que la\nfonction renvoie à l'appelant."
    },
    {
      "id": "q02",
      "difficulty": 1,
      "skills": [
        "appel"
      ],
      "title": "Appel de fonction",
      "partie": "definition",
      "statement": "Après `def carre(x): return x * x`, comment\nappelle-t-on cette fonction sur la valeur 5 ?",
      "options": [
        {
          "text": "`carre(5)`",
          "correct": true,
          "feedback": "Bonne réponse : parenthèses obligatoires,\nmême pour un seul paramètre. Renvoie 25.\n"
        },
        {
          "text": "`carre 5`",
          "correct": false,
          "feedback": "Erreur : il faut des parenthèses pour\nappeler une fonction en Python.\n"
        },
        {
          "text": "`call carre(5)`",
          "correct": false,
          "feedback": "Erreur : pas de mot-clé `call` en Python.\n"
        },
        {
          "text": "`carre[5]`",
          "correct": false,
          "feedback": "Erreur : les crochets sont pour\nl'indexation, pas l'appel de fonction.\n"
        }
      ],
      "explanation": "Sans parenthèses, `carre` désigne la fonction\nelle-même (un objet). Avec parenthèses,\n`carre(...)` invoque la fonction."
    },
    {
      "id": "q03",
      "difficulty": 1,
      "skills": [
        "return"
      ],
      "title": "Mot-clé return",
      "partie": "parametres",
      "statement": "À quoi sert l'instruction `return` ?",
      "options": [
        {
          "text": "À redémarrer la fonction",
          "correct": false,
          "feedback": "Le mot-clé `return` met\nfin à l'exécution de la\nfonction et fournit une\nvaleur à l'appelant. Il\nne relance jamais la\nfonction depuis le début.\n"
        },
        {
          "text": "À renvoyer une valeur et terminer la fonction",
          "correct": true,
          "feedback": "Bonne réponse : la fonction s'arrête au\n`return`, et la valeur passée est\ndisponible pour l'appelant.\n"
        },
        {
          "text": "À afficher directement le résultat dans la console",
          "correct": false,
          "feedback": "Erreur : c'est `print`. `return` produit\nune valeur de retour, sans affichage.\n"
        },
        {
          "text": "À déclarer une variable globale",
          "correct": false,
          "feedback": "Erreur : `return` ne déclare aucune variable.\nUne variable globale est simplement une\nvariable créée en dehors de toute fonction.\n"
        }
      ],
      "explanation": "Différence essentielle entre `print` et\n`return` : `print` affiche un message à\nl'utilisateur ; `return` produit une valeur\nutilisable dans le code (par exemple,\n`y = carre(3)`)."
    },
    {
      "id": "q04",
      "difficulty": 1,
      "skills": [
        "parametres"
      ],
      "title": "Paramètres",
      "partie": "parametres",
      "statement": "Quelle fonction a **deux** paramètres ?",
      "options": [
        {
          "text": "```python\ndef f(x):\n    return x\n```\n",
          "correct": false,
          "feedback": "Erreur : un seul paramètre.\n"
        },
        {
          "text": "```python\ndef f():\n    return 0\n```\n",
          "correct": false,
          "feedback": "Erreur : zéro paramètre.\n"
        },
        {
          "text": "```python\ndef f(x; y):\n    return x + y\n```\n",
          "correct": false,
          "feedback": "Erreur : le séparateur est la virgule, pas\nle point-virgule.\n"
        },
        {
          "text": "```python\ndef f(x, y):\n    return x + y\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : deux paramètres `x` et `y`\nséparés par une virgule.\n"
        }
      ],
      "explanation": "Vocabulaire : on parle de **paramètres** d'une\nfonction, à la fois pour leur nom dans la\ndéfinition (`def f(x, y):`) et pour les valeurs\nqu'on lui passe à l'appel (`f(3, 5)`)."
    },
    {
      "id": "q05",
      "difficulty": 1,
      "skills": [
        "sans-retour"
      ],
      "title": "Fonction sans return",
      "partie": "parametres",
      "statement": "Que renvoie une fonction qui ne contient **aucun `return`** ?",
      "options": [
        {
          "text": "`None`",
          "correct": true,
          "feedback": "Bonne réponse : Python renvoie\nimplicitement `None` (la valeur « rien »).\nC'est le cas typique des fonctions qui se\ncontentent d'afficher ou de modifier\nquelque chose, sans renvoyer de valeur.\n"
        },
        {
          "text": "Une erreur",
          "correct": false,
          "feedback": "Erreur : pas d'erreur.\n"
        },
        {
          "text": "Une chaîne vide `\"\"`",
          "correct": false,
          "feedback": "Erreur : la valeur par défaut est `None`.\n"
        },
        {
          "text": "`0`",
          "correct": false,
          "feedback": "Erreur : ce n'est pas la valeur par défaut.\n"
        }
      ],
      "explanation": "Souvent, on n'utilise pas la valeur de retour\nde telles fonctions (on ne fait pas\n`x = print(...)`). Mais elle existe (`None`)."
    },
    {
      "id": "q06",
      "difficulty": 1,
      "skills": [
        "fonctions-natives"
      ],
      "title": "Fonctions natives",
      "partie": "definition",
      "statement": "Parmi les suivants, lequel n'est **pas** une\nfonction native de Python ?",
      "options": [
        {
          "text": "`carre(...)`",
          "correct": true,
          "feedback": "Bonne réponse : `carre` n'est pas natif,\nc'est une fonction qu'il faut définir\nsoi-même.\n"
        },
        {
          "text": "`type(...)`",
          "correct": false,
          "feedback": "C'est bien une fonction native (renvoie le\ntype).\n"
        },
        {
          "text": "`len(...)`",
          "correct": false,
          "feedback": "C'est bien une fonction native (longueur).\n"
        },
        {
          "text": "`max(...)`",
          "correct": false,
          "feedback": "C'est bien une fonction native (maximum).\n"
        }
      ],
      "explanation": "Fonctions natives utiles : `print`, `input`,\n`len`, `range`, `type`, `int`, `float`, `str`,\n`bool`, `min`, `max`, `sum`, `abs`, `round`,\n`sorted`, etc."
    },
    {
      "id": "q07",
      "difficulty": 1,
      "skills": [
        "appel",
        "composition"
      ],
      "title": "Plusieurs appels",
      "partie": "definition",
      "statement": "```python\ndef double(x):\n    return x * 2\na = double(3)\nb = double(double(5))\n```\nQue valent `a` et `b` ?",
      "options": [
        {
          "text": "a = 6, b = 20",
          "correct": true,
          "feedback": "Bonne réponse : a = double(3) = 6 ;\nb = double(double(5)) = double(10) = 20.\n"
        },
        {
          "text": "a = 6, b = 25",
          "correct": false,
          "feedback": "Erreur : 25 = 5², mais on multiplie par 2,\npas un carré.\n"
        },
        {
          "text": "a = 3, b = 5",
          "correct": false,
          "feedback": "Erreur : on n'a pas appelé la fonction.\n"
        },
        {
          "text": "a = 6, b = 10",
          "correct": false,
          "feedback": "Erreur sur b : `double(double(5))` =\n`double(10)` = 20.\n"
        }
      ],
      "explanation": "Composition de fonctions : `f(g(x))` évalue\nd'abord `g(x)` puis applique `f`. Lecture de\nl'intérieur vers l'extérieur.",
      "variants": [
        {
          "statement": "```python\ndef double(x):\n    return x * 2\na = double(3)\nb = double(double(5))\n```\nQue valent `a` et `b` ?",
          "options": [
            {
              "text": "a = 6, b = 20",
              "correct": true,
              "feedback": "Bonne réponse : a = double(3) = 6 ;\nb = double(double(5)) = double(10) = 20.\n"
            },
            {
              "text": "a = 6, b = 25",
              "correct": false,
              "feedback": "Erreur : 25 = 5², mais on multiplie par 2,\npas un carré.\n"
            },
            {
              "text": "a = 3, b = 5",
              "correct": false,
              "feedback": "Erreur : on n'a pas appelé la fonction.\n"
            },
            {
              "text": "a = 6, b = 10",
              "correct": false,
              "feedback": "Erreur sur b : `double(double(5))` =\n`double(10)` = 20.\n"
            }
          ],
          "explanation": "Composition de fonctions : `f(g(x))` évalue\nd'abord `g(x)` puis applique `f`. Lecture de\nl'intérieur vers l'extérieur."
        },
        {
          "statement": "```python\ndef triple(x):\n    return x * 3\na = triple(4)\nb = triple(triple(5))\n```\nQue valent `a` et `b` ?",
          "options": [
            {
              "text": "a = 12, b = 45",
              "correct": true,
              "feedback": "Bonne réponse : a = triple(4) = 12 ;\nb = triple(triple(5)) = triple(15) = 45.\n"
            },
            {
              "text": "a = 12, b = 25",
              "correct": false,
              "feedback": "Erreur : 25 = 5², mais on multiplie par 3,\npas un carré.\n"
            },
            {
              "text": "a = 4, b = 5",
              "correct": false,
              "feedback": "Erreur : on n'a pas appelé la fonction.\n"
            },
            {
              "text": "a = 12, b = 15",
              "correct": false,
              "feedback": "Erreur sur b : `triple(triple(5))` =\n`triple(15)` = 45.\n"
            }
          ],
          "explanation": "Composition de fonctions : `f(g(x))` évalue\nd'abord `g(x)` puis applique `f`. Lecture de\nl'intérieur vers l'extérieur."
        },
        {
          "statement": "```python\ndef double(x):\n    return x * 2\na = double(2)\nb = double(double(6))\n```\nQue valent `a` et `b` ?",
          "options": [
            {
              "text": "a = 4, b = 24",
              "correct": true,
              "feedback": "Bonne réponse : a = double(2) = 4 ;\nb = double(double(6)) = double(12) = 24.\n"
            },
            {
              "text": "a = 4, b = 36",
              "correct": false,
              "feedback": "Erreur : 36 = 6², mais on multiplie par 2,\npas un carré.\n"
            },
            {
              "text": "a = 2, b = 6",
              "correct": false,
              "feedback": "Erreur : on n'a pas appelé la fonction.\n"
            },
            {
              "text": "a = 4, b = 12",
              "correct": false,
              "feedback": "Erreur sur b : `double(double(6))` =\n`double(12)` = 24.\n"
            }
          ],
          "explanation": "Composition de fonctions : `f(g(x))` évalue\nd'abord `g(x)` puis applique `f`. Lecture de\nl'intérieur vers l'extérieur."
        }
      ]
    },
    {
      "id": "q08",
      "difficulty": 1,
      "skills": [
        "docstring"
      ],
      "title": "Docstring",
      "partie": "definition",
      "statement": "Que fait la première ligne en triples\nguillemets dans une fonction ?\n```python\ndef carre(x):\n    \"\"\"Renvoie le carré de x.\"\"\"\n    return x * x\n```",
      "options": [
        {
          "text": "C'est une docstring, que `help(carre)` affiche",
          "correct": true,
          "feedback": "Bonne réponse : c'est la manière standard de documenter une fonction en Python. Très utile pour la maintenance et pour l'aide affichée par `help`.\n"
        },
        {
          "text": "C'est obligatoire pour que la fonction marche",
          "correct": false,
          "feedback": "Erreur : facultatif.\n"
        },
        {
          "text": "C'est un commentaire ignoré par Python",
          "correct": false,
          "feedback": "Erreur : c'est plus qu'un commentaire, c'est une **docstring**, conservée avec la fonction et affichée par `help(carre)`.\n"
        },
        {
          "text": "C'est un test unitaire automatique de la fonction",
          "correct": false,
          "feedback": "Erreur : un test serait un `assert`.\n"
        }
      ],
      "explanation": "Bonne pratique : toujours documenter ses fonctions, avec une description courte sur la première ligne de la docstring, puis les détails utiles."
    },
    {
      "id": "q09",
      "difficulty": 1,
      "skills": [
        "scope"
      ],
      "title": "Variable locale",
      "partie": "portee",
      "statement": "Le code suivant lève-t-il une erreur ?\n```python\ndef f():\n    x = 5\n\nf()\nprint(x)\n```",
      "options": [
        {
          "text": "Non, il affiche `0`",
          "correct": false,
          "feedback": "Erreur : aucune valeur par défaut.\n"
        },
        {
          "text": "Non, mais il affiche `None`",
          "correct": false,
          "feedback": "Erreur : pas de retour silencieux.\n"
        },
        {
          "text": "Non, le programme affiche tranquillement la valeur 5",
          "correct": false,
          "feedback": "Erreur : `x` est **locale** à `f`, pas\naccessible à l'extérieur.\n"
        },
        {
          "text": "Oui : `NameError`, `x` n'existe pas hors de `f`",
          "correct": true,
          "feedback": "Bonne réponse : la **portée** des variables\nlocales est limitée à la fonction.\n"
        }
      ],
      "explanation": "Notion clé : la **portée** (ou scope). Une\nvariable créée dans une fonction n'existe\nqu'à l'intérieur de cette fonction."
    },
    {
      "id": "q10",
      "difficulty": 1,
      "skills": [
        "exemple-simple"
      ],
      "title": "Trace simple",
      "partie": "definition",
      "statement": "Que fait ce code ?\n```python\ndef saluer(nom):\n    print(\"Bonjour\", nom)\n\nsaluer(\"Alice\")\n```",
      "options": [
        {
          "text": "Lève une erreur",
          "correct": false,
          "feedback": "Erreur : code valide.\n"
        },
        {
          "text": "Affiche `Bonjour Alice`",
          "correct": true,
          "feedback": "Bonne réponse : la fonction reçoit `nom =\n\"Alice\"`, puis `print` affiche les deux\nparamètres séparés par un espace.\n"
        },
        {
          "text": "Renvoie la chaîne `\"Bonjour Alice\"` mais sans afficher",
          "correct": false,
          "feedback": "Erreur : `print` affiche, et la fonction n'a\npas de `return`.\n"
        },
        {
          "text": "N'affiche rien",
          "correct": false,
          "feedback": "Erreur : `print` produit un affichage.\n"
        }
      ],
      "explanation": "Distinguer `print` (afficher quelque chose à\nl'écran) de `return` (renvoyer une valeur à\nl'appelant). Ici, la fonction se contente\nd'afficher."
    },
    {
      "id": "q11",
      "difficulty": 2,
      "skills": [
        "params-defaut"
      ],
      "title": "Paramètre par défaut",
      "partie": "parametres",
      "statement": "Que donne ce code ?\n```python\ndef saluer(nom=\"ami\"):\n    return \"Bonjour \" + nom\n\nprint(saluer())\nprint(saluer(\"Alice\"))\n```",
      "options": [
        {
          "text": "```\nErreur\nBonjour Alice\n```\n",
          "correct": false,
          "feedback": "Erreur : avec un paramètre par défaut,\nl'appel sans paramètre est valide.\n"
        },
        {
          "text": "```\nBonjour ami\nBonjour Alice\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : `nom=\"ami\"` est la valeur\npar défaut. Si on n'en passe pas,\nle paramètre vaut `\"ami\"`.\n"
        },
        {
          "text": "```\nBonjour ami\nBonjour ami\n```\n",
          "correct": false,
          "feedback": "Erreur : le second appel passe `\"Alice\"`,\nqui remplace la valeur par défaut.\n"
        },
        {
          "text": "```\nBonjour\nBonjour Alice\n```\n",
          "correct": false,
          "feedback": "Erreur : la valeur par défaut est `\"ami\"`,\npas une chaîne vide.\n"
        }
      ],
      "explanation": "Les paramètres par défaut rendent les\nfonctions plus flexibles. Convention : les\nparamètres avec valeur par défaut viennent\n**après** les paramètres sans."
    },
    {
      "id": "q12",
      "difficulty": 2,
      "skills": [
        "args-positionnel-nomme"
      ],
      "title": "Paramètres nommés",
      "partie": "parametres",
      "statement": "Quelle est la différence entre\n`puissance(2, 10)` et\n`puissance(base=2, exposant=10)` ?",
      "options": [
        {
          "text": "La seconde forme ne marche que pour les fonctions natives",
          "correct": false,
          "feedback": "Erreur : les paramètres nommés marchent\npour toutes les fonctions.\n"
        },
        {
          "text": "La première forme est aujourd'hui complètement obsolète",
          "correct": false,
          "feedback": "Erreur : très utilisée.\n"
        },
        {
          "text": "La seconde forme est plus rapide",
          "correct": false,
          "feedback": "Erreur : aucune différence de performance.\n"
        },
        {
          "text": "Aucune, les deux sont équivalents pour `def puissance(base, exposant):`",
          "correct": true,
          "feedback": "Bonne réponse : on peut passer des\nparamètres **positionnellement** (par\nordre) ou **nommés** (par mot-clé).\nL'ordre n'importe pas pour les nommés.\n"
        }
      ],
      "explanation": "Les paramètres nommés améliorent la lisibilité, surtout quand un appel a beaucoup de paramètres : dans `puissance(base=2, exposant=10)`, le rôle de chaque valeur se lit directement."
    },
    {
      "id": "q13",
      "difficulty": 2,
      "skills": [
        "portee",
        "globale"
      ],
      "title": "Variable globale",
      "partie": "portee",
      "statement": "Quel est le résultat ?\n```python\nx = 10\ndef f():\n    return x + 1\nprint(f())\n```",
      "options": [
        {
          "text": "Erreur (x non défini)",
          "correct": false,
          "feedback": "Erreur : `f` peut **lire** les variables du\nscope englobant.\n"
        },
        {
          "text": "11",
          "correct": true,
          "feedback": "Bonne réponse : `x` est une variable\n**globale**. La fonction peut la lire ; une\naffectation `x = ...` dans `f` créerait au\ncontraire une variable locale distincte.\n"
        },
        {
          "text": "Aucune sortie",
          "correct": false,
          "feedback": "Erreur : `print(f())` affiche.\n"
        },
        {
          "text": "10",
          "correct": false,
          "feedback": "Erreur : on ajoute 1.\n"
        }
      ],
      "explanation": "Règle d'or : préférer **passer en paramètre**\nplutôt qu'utiliser des variables globales.\nCode plus testable et plus prévisible.",
      "variants": [
        {
          "statement": "Quel est le résultat ?\n```python\nx = 10\ndef f():\n    return x + 1\nprint(f())\n```",
          "options": [
            {
              "text": "Erreur (x non défini)",
              "correct": false,
              "feedback": "Erreur : `f` peut **lire** les variables du\nscope englobant.\n"
            },
            {
              "text": "11",
              "correct": true,
              "feedback": "Bonne réponse : `x` est une variable\n**globale**. La fonction peut la lire ; une\naffectation `x = ...` dans `f` créerait au\ncontraire une variable locale distincte.\n"
            },
            {
              "text": "Aucune sortie",
              "correct": false,
              "feedback": "Erreur : `print(f())` affiche.\n"
            },
            {
              "text": "10",
              "correct": false,
              "feedback": "Erreur : on ajoute 1.\n"
            }
          ],
          "explanation": "Règle d'or : préférer **passer en paramètre**\nplutôt qu'utiliser des variables globales.\nCode plus testable et plus prévisible."
        },
        {
          "statement": "Quel est le résultat ?\n```python\nx = 25\ndef f():\n    return x + 1\nprint(f())\n```",
          "options": [
            {
              "text": "Erreur (x non défini)",
              "correct": false,
              "feedback": "Erreur : `f` peut **lire** les variables du\nscope englobant.\n"
            },
            {
              "text": "26",
              "correct": true,
              "feedback": "Bonne réponse : `x` est une variable\n**globale**. La fonction peut la lire ; une\naffectation `x = ...` dans `f` créerait au\ncontraire une variable locale distincte.\n"
            },
            {
              "text": "Aucune sortie",
              "correct": false,
              "feedback": "Erreur : `print(f())` affiche.\n"
            },
            {
              "text": "25",
              "correct": false,
              "feedback": "Erreur : on ajoute 1.\n"
            }
          ],
          "explanation": "Règle d'or : préférer **passer en paramètre**\nplutôt qu'utiliser des variables globales.\nCode plus testable et plus prévisible."
        },
        {
          "statement": "Quel est le résultat ?\n```python\nx = 7\ndef f():\n    return x + 5\nprint(f())\n```",
          "options": [
            {
              "text": "Erreur (x non défini)",
              "correct": false,
              "feedback": "Erreur : `f` peut **lire** les variables du\nscope englobant.\n"
            },
            {
              "text": "12",
              "correct": true,
              "feedback": "Bonne réponse : `x` est une variable\n**globale**. La fonction peut la lire ; une\naffectation `x = ...` dans `f` créerait au\ncontraire une variable locale distincte.\n"
            },
            {
              "text": "Aucune sortie",
              "correct": false,
              "feedback": "Erreur : `print(f())` affiche.\n"
            },
            {
              "text": "7",
              "correct": false,
              "feedback": "Erreur : on ajoute 5.\n"
            }
          ],
          "explanation": "Règle d'or : préférer **passer en paramètre**\nplutôt qu'utiliser des variables globales.\nCode plus testable et plus prévisible."
        }
      ]
    },
    {
      "id": "q14",
      "difficulty": 2,
      "skills": [
        "parametres",
        "retour"
      ],
      "title": "Valeur de retour non récupérée",
      "partie": "parametres",
      "statement": "Quel est le résultat ?\n```python\ndef incremente(n):\n    n = n + 1\n    return n\ncompteur = 5\nincremente(compteur)\nprint(compteur)\n```",
      "options": [
        {
          "text": "`6`, car le paramètre `n` désigne la variable `compteur`",
          "correct": false,
          "feedback": "Erreur : `n` est une variable locale qui reçoit\nla **valeur** $5$. L'affectation `n = n + 1`\nmodifie `n` seule ; `compteur` n'est pas touchée.\n"
        },
        {
          "text": "`6`, car `return n` met à jour `compteur`",
          "correct": false,
          "feedback": "Erreur : `return` transmet une valeur à\nl'appelant, il n'écrit dans aucune variable.\nComme l'appel `incremente(compteur)` n'est pas\naffecté, la valeur $6$ renvoyée est perdue.\n"
        },
        {
          "text": "`5`, car la valeur renvoyée n'est pas récupérée",
          "correct": true,
          "feedback": "Bonne réponse : la fonction calcule et renvoie\n$6$, mais l'appel `incremente(compteur)` ne fait\nrien de cette valeur. Pour mettre à jour le\ncompteur, il faut écrire\n`compteur = incremente(compteur)`.\n"
        },
        {
          "text": "`5` puis `6` sur deux lignes, car `return` affiche la valeur",
          "correct": false,
          "feedback": "Erreur : `return` n'affiche rien, seul `print`\nécrit à l'écran. Une seule ligne apparaît, celle\nde `print(compteur)`, qui vaut toujours $5$.\n"
        }
      ],
      "explanation": "Passer par un paramètre et une valeur de retour est\nla bonne façon de mettre à jour une variable depuis\nune fonction : `compteur = incremente(compteur)`.\nSans cette réaffectation, la valeur renvoyée est\nsimplement perdue.",
      "variants": [
        {
          "statement": "Quel est le résultat ?\n```python\ndef incremente(n):\n    n = n + 1\n    return n\ncompteur = 5\nincremente(compteur)\nprint(compteur)\n```",
          "options": [
            {
              "text": "`6`, car le paramètre `n` désigne la variable `compteur`",
              "correct": false,
              "feedback": "Erreur : `n` est une variable locale qui reçoit\nla **valeur** $5$. L'affectation `n = n + 1`\nmodifie `n` seule ; `compteur` n'est pas touchée.\n"
            },
            {
              "text": "`6`, car `return n` met à jour `compteur`",
              "correct": false,
              "feedback": "Erreur : `return` transmet une valeur à\nl'appelant, il n'écrit dans aucune variable.\nComme l'appel `incremente(compteur)` n'est pas\naffecté, la valeur $6$ renvoyée est perdue.\n"
            },
            {
              "text": "`5`, car la valeur renvoyée n'est pas récupérée",
              "correct": true,
              "feedback": "Bonne réponse : la fonction calcule et renvoie\n$6$, mais l'appel `incremente(compteur)` ne fait\nrien de cette valeur. Pour mettre à jour le\ncompteur, il faut écrire\n`compteur = incremente(compteur)`.\n"
            },
            {
              "text": "`5` puis `6` sur deux lignes, car `return` affiche la valeur",
              "correct": false,
              "feedback": "Erreur : `return` n'affiche rien, seul `print`\nécrit à l'écran. Une seule ligne apparaît, celle\nde `print(compteur)`, qui vaut toujours $5$.\n"
            }
          ],
          "explanation": "Passer par un paramètre et une valeur de retour est\nla bonne façon de mettre à jour une variable depuis\nune fonction : `compteur = incremente(compteur)`.\nSans cette réaffectation, la valeur renvoyée est\nsimplement perdue."
        },
        {
          "statement": "Quel est le résultat ?\n```python\ndef incremente(n):\n    n = n + 1\n    return n\ncompteur = 12\nincremente(compteur)\nprint(compteur)\n```",
          "options": [
            {
              "text": "`13`, car le paramètre `n` désigne la variable `compteur`",
              "correct": false,
              "feedback": "Erreur : `n` est une variable locale qui reçoit\nla **valeur** $12$. L'affectation `n = n + 1`\nmodifie `n` seule ; `compteur` n'est pas touchée.\n"
            },
            {
              "text": "`13`, car `return n` met à jour `compteur`",
              "correct": false,
              "feedback": "Erreur : `return` transmet une valeur à\nl'appelant, il n'écrit dans aucune variable.\nComme l'appel `incremente(compteur)` n'est pas\naffecté, la valeur $13$ renvoyée est perdue.\n"
            },
            {
              "text": "`12`, car la valeur renvoyée n'est pas récupérée",
              "correct": true,
              "feedback": "Bonne réponse : la fonction calcule et renvoie\n$13$, mais l'appel `incremente(compteur)` ne fait\nrien de cette valeur. Pour mettre à jour le\ncompteur, il faut écrire\n`compteur = incremente(compteur)`.\n"
            },
            {
              "text": "`12` puis `13` sur deux lignes, car `return` affiche la valeur",
              "correct": false,
              "feedback": "Erreur : `return` n'affiche rien, seul `print`\nécrit à l'écran. Une seule ligne apparaît, celle\nde `print(compteur)`, qui vaut toujours $12$.\n"
            }
          ],
          "explanation": "Passer par un paramètre et une valeur de retour est\nla bonne façon de mettre à jour une variable depuis\nune fonction : `compteur = incremente(compteur)`.\nSans cette réaffectation, la valeur renvoyée est\nsimplement perdue."
        },
        {
          "statement": "Quel est le résultat ?\n```python\ndef incremente(n):\n    n = n + 1\n    return n\ncompteur = 41\nincremente(compteur)\nprint(compteur)\n```",
          "options": [
            {
              "text": "`42`, car le paramètre `n` désigne la variable `compteur`",
              "correct": false,
              "feedback": "Erreur : `n` est une variable locale qui reçoit\nla **valeur** $41$. L'affectation `n = n + 1`\nmodifie `n` seule ; `compteur` n'est pas touchée.\n"
            },
            {
              "text": "`42`, car `return n` met à jour `compteur`",
              "correct": false,
              "feedback": "Erreur : `return` transmet une valeur à\nl'appelant, il n'écrit dans aucune variable.\nComme l'appel `incremente(compteur)` n'est pas\naffecté, la valeur $42$ renvoyée est perdue.\n"
            },
            {
              "text": "`41`, car la valeur renvoyée n'est pas récupérée",
              "correct": true,
              "feedback": "Bonne réponse : la fonction calcule et renvoie\n$42$, mais l'appel `incremente(compteur)` ne fait\nrien de cette valeur. Pour mettre à jour le\ncompteur, il faut écrire\n`compteur = incremente(compteur)`.\n"
            },
            {
              "text": "`41` puis `42` sur deux lignes, car `return` affiche la valeur",
              "correct": false,
              "feedback": "Erreur : `return` n'affiche rien, seul `print`\nécrit à l'écran. Une seule ligne apparaît, celle\nde `print(compteur)`, qui vaut toujours $41$.\n"
            }
          ],
          "explanation": "Passer par un paramètre et une valeur de retour est\nla bonne façon de mettre à jour une variable depuis\nune fonction : `compteur = incremente(compteur)`.\nSans cette réaffectation, la valeur renvoyée est\nsimplement perdue."
        }
      ]
    },
    {
      "id": "q15",
      "difficulty": 2,
      "skills": [
        "retour-multiple"
      ],
      "title": "Retour multiple",
      "partie": "parametres",
      "statement": "Que renvoie cette fonction ?\n```python\ndef min_max(liste):\n    return min(liste), max(liste)\n```",
      "options": [
        {
          "text": "Un tuple `(min, max)`",
          "correct": true,
          "feedback": "Bonne réponse : Python utilise les tuples\npour les retours multiples. À la\nréception : `mn, mx = min_max(liste)`\n(déballage).\n"
        },
        {
          "text": "Une liste de deux éléments",
          "correct": false,
          "feedback": "Erreur : virgule sans crochets = tuple.\n"
        },
        {
          "text": "Un dictionnaire",
          "correct": false,
          "feedback": "Erreur : un dict s'écrit avec `{}`.\n"
        },
        {
          "text": "Erreur : on ne peut pas avoir deux retours",
          "correct": false,
          "feedback": "Erreur : Python le permet via le tuple.\n"
        }
      ],
      "explanation": "Idiome courant : renvoyer plusieurs valeurs d'un coup sous forme de p-uplet. Pratique pour les petites fonctions utilitaires."
    },
    {
      "id": "q17",
      "difficulty": 2,
      "skills": [
        "portee",
        "locale"
      ],
      "title": "Portée locale",
      "partie": "portee",
      "statement": "```python\nx = 10\ndef f():\n    x = 20\n    print(x)\nf()\nprint(x)\n```\nQu'affiche ce code ?",
      "options": [
        {
          "text": "```\n10\n10\n```\n",
          "correct": false,
          "feedback": "Erreur : la fonction affiche bien 20 (sa\nlocale).\n"
        },
        {
          "text": "Une exception",
          "correct": false,
          "feedback": "Erreur : code valide.\n"
        },
        {
          "text": "```\n20\n20\n```\n",
          "correct": false,
          "feedback": "Erreur : le `x` interne à `f` est une\nvariable **locale** distincte de la\nvariable globale.\n"
        },
        {
          "text": "```\n20\n10\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : l'affectation `x = 20`\ndans la fonction crée une variable\n**locale** ; elle masque la globale le\ntemps de l'appel mais ne la modifie pas.\nAprès l'appel, la globale vaut toujours\n10.\n"
        }
      ],
      "explanation": "Notion de **portée** (scope) : une variable\ndéfinie dans une fonction n'existe qu'à\nl'intérieur. C'est précieux pour\nl'isolation, mais source de confusion\nclassique.",
      "variants": [
        {
          "statement": "```python\nx = 10\ndef f():\n    x = 20\n    print(x)\nf()\nprint(x)\n```\nQu'affiche ce code ?",
          "options": [
            {
              "text": "```\n10\n10\n```\n",
              "correct": false,
              "feedback": "Erreur : la fonction affiche bien 20 (sa\nlocale).\n"
            },
            {
              "text": "Une exception",
              "correct": false,
              "feedback": "Erreur : code valide.\n"
            },
            {
              "text": "```\n20\n20\n```\n",
              "correct": false,
              "feedback": "Erreur : le `x` interne à `f` est une\nvariable **locale** distincte de la\nvariable globale.\n"
            },
            {
              "text": "```\n20\n10\n```\n",
              "correct": true,
              "feedback": "Bonne réponse : l'affectation `x = 20`\ndans la fonction crée une variable\n**locale** ; elle masque la globale le\ntemps de l'appel mais ne la modifie pas.\nAprès l'appel, la globale vaut toujours\n10.\n"
            }
          ],
          "explanation": "Notion de **portée** (scope) : une variable\ndéfinie dans une fonction n'existe qu'à\nl'intérieur. C'est précieux pour\nl'isolation, mais source de confusion\nclassique."
        },
        {
          "statement": "```python\nx = 5\ndef f():\n    x = 50\n    print(x)\nf()\nprint(x)\n```\nQu'affiche ce code ?",
          "options": [
            {
              "text": "```\n5\n5\n```\n",
              "correct": false,
              "feedback": "Erreur : la fonction affiche bien 50 (sa\nlocale).\n"
            },
            {
              "text": "Une exception",
              "correct": false,
              "feedback": "Erreur : code valide.\n"
            },
            {
              "text": "```\n50\n50\n```\n",
              "correct": false,
              "feedback": "Erreur : le `x` interne à `f` est une\nvariable **locale** distincte de la\nvariable globale.\n"
            },
            {
              "text": "```\n50\n5\n```\n",
              "correct": true,
              "feedback": "Bonne réponse : l'affectation `x = 50`\ndans la fonction crée une variable\n**locale** ; elle masque la globale le\ntemps de l'appel mais ne la modifie pas.\nAprès l'appel, la globale vaut toujours\n5.\n"
            }
          ],
          "explanation": "Notion de **portée** (scope) : une variable\ndéfinie dans une fonction n'existe qu'à\nl'intérieur. C'est précieux pour\nl'isolation, mais source de confusion\nclassique."
        },
        {
          "statement": "```python\nx = 1\ndef f():\n    x = 2\n    print(x)\nf()\nprint(x)\n```\nQu'affiche ce code ?",
          "options": [
            {
              "text": "```\n1\n1\n```\n",
              "correct": false,
              "feedback": "Erreur : la fonction affiche bien 2 (sa\nlocale).\n"
            },
            {
              "text": "Une exception",
              "correct": false,
              "feedback": "Erreur : code valide.\n"
            },
            {
              "text": "```\n2\n2\n```\n",
              "correct": false,
              "feedback": "Erreur : le `x` interne à `f` est une\nvariable **locale** distincte de la\nvariable globale.\n"
            },
            {
              "text": "```\n2\n1\n```\n",
              "correct": true,
              "feedback": "Bonne réponse : l'affectation `x = 2`\ndans la fonction crée une variable\n**locale** ; elle masque la globale le\ntemps de l'appel mais ne la modifie pas.\nAprès l'appel, la globale vaut toujours\n1.\n"
            }
          ],
          "explanation": "Notion de **portée** (scope) : une variable\ndéfinie dans une fonction n'existe qu'à\nl'intérieur. C'est précieux pour\nl'isolation, mais source de confusion\nclassique."
        }
      ]
    },
    {
      "id": "q18",
      "difficulty": 2,
      "skills": [
        "retour-vs-affichage"
      ],
      "title": "Renvoyer ou afficher ?",
      "partie": "parametres",
      "statement": "Quelle est la différence entre une fonction qui\n**renvoie** une valeur et une fonction qui\n**affiche** une valeur ?",
      "options": [
        {
          "text": "L'instruction `print` s'exécute plus rapidement que `return`",
          "correct": false,
          "feedback": "Erreur : la performance n'est pas le sujet.\n"
        },
        {
          "text": "`return` transmet une valeur à l'appelant, `print` l'affiche",
          "correct": true,
          "feedback": "Bonne réponse : une valeur renvoyée peut être\nstockée dans une variable, transmise à une\nautre fonction, comparée. `print` se contente\nd'écrire un texte à l'écran et ne renvoie\nrien (`None`). Si on a besoin de la valeur,\nil faut un `return`.\n"
        },
        {
          "text": "`return` n'existe pas en Python, on utilise toujours `print`",
          "correct": false,
          "feedback": "Erreur : `return` est l'instruction standard\npour renvoyer une valeur depuis une\nfonction.\n"
        },
        {
          "text": "Aucune différence, les deux transmettent la valeur à l'appelant",
          "correct": false,
          "feedback": "Erreur : la confusion entre les deux est l'un\ndes bugs les plus classiques. `print` ne\nrend rien d'exploitable.\n"
        }
      ],
      "explanation": "Bug classique : écrire `def carre(x): print(x*x)`\nau lieu de `def carre(x): return x*x`. Avec la\npremière version, on ne peut pas faire\n`y = carre(3) * 2` : `y` vaut `None`. La\nseconde version permet bien `y = 18`."
    },
    {
      "id": "q19",
      "difficulty": 2,
      "skills": [
        "debug-print-vs-return"
      ],
      "title": "print vs return",
      "partie": "portee",
      "statement": "Pourquoi ce code n'affiche-t-il **rien** sur la\nconsole ?\n```python\ndef carre(x):\n    return x * x\n\ncarre(5)\n```",
      "options": [
        {
          "text": "Parce que la fonction n'est pas appelée",
          "correct": false,
          "feedback": "Erreur : `carre(5)` est bien un appel.\n"
        },
        {
          "text": "Parce que `5` n'est pas un entier",
          "correct": false,
          "feedback": "Erreur : 5 est un entier.\n"
        },
        {
          "text": "Parce que `return` n'affiche pas : la valeur 25 est ignorée",
          "correct": true,
          "feedback": "Bonne réponse : pour voir un affichage,\nécrire `print(carre(5))` ou modifier la\nfonction pour utiliser `print` (mais\nalors plus de retour).\n"
        },
        {
          "text": "Parce que la fonction contient manifestement un bug",
          "correct": false,
          "feedback": "Erreur : la fonction est correcte, elle\nrenvoie 25.\n"
        }
      ],
      "explanation": "Confusion classique des débutants : penser\nque `return` affiche. `print` et `return`\nsont **deux mécanismes différents**."
    },
    {
      "id": "q20",
      "difficulty": 2,
      "skills": [
        "decomposition"
      ],
      "title": "Décomposer",
      "partie": "definition",
      "statement": "Pourquoi est-il recommandé de **décomposer** un\nprogramme en fonctions ?",
      "options": [
        {
          "text": "Pour économiser une quantité notable de mémoire vive",
          "correct": false,
          "feedback": "Erreur : pas un avantage notable.\n"
        },
        {
          "text": "Parce que le compilateur le demande",
          "correct": false,
          "feedback": "Erreur : Python est interprété, et il ne\nl'exige pas.\n"
        },
        {
          "text": "Pour la lisibilité, la réutilisation et la testabilité du code",
          "correct": true,
          "feedback": "Bonne réponse : décomposer un problème en sous-problèmes, chacun confié à une fonction, est un principe fondamental de la programmation. Une fonction courte et bien nommée vaut mieux qu'un gros bloc de code.\n"
        },
        {
          "text": "Parce que c'est plus court d'écrire",
          "correct": false,
          "feedback": "Pas forcément plus court : c'est même\nparfois plus long.\n"
        }
      ],
      "explanation": "Maxime : « une fonction, une responsabilité ». Si une fonction fait plusieurs choses, il vaut mieux la découper en plusieurs petites fonctions."
    },
    {
      "id": "q21",
      "difficulty": 3,
      "skills": [
        "portee",
        "ombrage"
      ],
      "title": "Piège de portée",
      "partie": "portee",
      "statement": "```python\nx = 10\ndef f():\n    x = 20\n    return x\nprint(f())\nprint(x)\n```\nQuel est le résultat ?",
      "options": [
        {
          "text": "```\n10\n10\n```\n",
          "correct": false,
          "feedback": "Erreur : `f()` renvoie sa propre `x` locale\n(= 20).\n"
        },
        {
          "text": "```\n20\n20\n```\n",
          "correct": false,
          "feedback": "Erreur : le `x = 20` dans `f` crée une\nvariable **locale**, qui ne modifie pas la\nglobale.\n"
        },
        {
          "text": "```\n20\n10\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : `x` à l'intérieur de `f`\nest local et masque la globale. À l'extérieur,\nla globale `x` reste à 10.\n"
        },
        {
          "text": "Erreur",
          "correct": false,
          "feedback": "Erreur : aucune erreur.\n"
        }
      ],
      "explanation": "Cas typique d'**ombrage** (shadowing). Source\nde confusion fréquente. Pour éviter,\nprivilégier le passage en paramètre.",
      "variants": [
        {
          "statement": "```python\nx = 10\ndef f():\n    x = 20\n    return x\nprint(f())\nprint(x)\n```\nQuel est le résultat ?",
          "options": [
            {
              "text": "```\n10\n10\n```\n",
              "correct": false,
              "feedback": "Erreur : `f()` renvoie sa propre `x` locale\n(= 20).\n"
            },
            {
              "text": "```\n20\n20\n```\n",
              "correct": false,
              "feedback": "Erreur : le `x = 20` dans `f` crée une\nvariable **locale**, qui ne modifie pas la\nglobale.\n"
            },
            {
              "text": "```\n20\n10\n```\n",
              "correct": true,
              "feedback": "Bonne réponse : `x` à l'intérieur de `f`\nest local et masque la globale. À l'extérieur,\nla globale `x` reste à 10.\n"
            },
            {
              "text": "Erreur",
              "correct": false,
              "feedback": "Erreur : aucune erreur.\n"
            }
          ],
          "explanation": "Cas typique d'**ombrage** (shadowing). Source\nde confusion fréquente. Pour éviter,\nprivilégier le passage en paramètre."
        },
        {
          "statement": "```python\nx = 3\ndef f():\n    x = 30\n    return x\nprint(f())\nprint(x)\n```\nQuel est le résultat ?",
          "options": [
            {
              "text": "```\n3\n3\n```\n",
              "correct": false,
              "feedback": "Erreur : `f()` renvoie sa propre `x` locale\n(= 30).\n"
            },
            {
              "text": "```\n30\n30\n```\n",
              "correct": false,
              "feedback": "Erreur : le `x = 30` dans `f` crée une\nvariable **locale**, qui ne modifie pas la\nglobale.\n"
            },
            {
              "text": "```\n30\n3\n```\n",
              "correct": true,
              "feedback": "Bonne réponse : `x` à l'intérieur de `f`\nest local et masque la globale. À l'extérieur,\nla globale `x` reste à 3.\n"
            },
            {
              "text": "Erreur",
              "correct": false,
              "feedback": "Erreur : aucune erreur.\n"
            }
          ],
          "explanation": "Cas typique d'**ombrage** (shadowing). Source\nde confusion fréquente. Pour éviter,\nprivilégier le passage en paramètre."
        },
        {
          "statement": "```python\nx = 100\ndef f():\n    x = 200\n    return x\nprint(f())\nprint(x)\n```\nQuel est le résultat ?",
          "options": [
            {
              "text": "```\n100\n100\n```\n",
              "correct": false,
              "feedback": "Erreur : `f()` renvoie sa propre `x` locale\n(= 200).\n"
            },
            {
              "text": "```\n200\n200\n```\n",
              "correct": false,
              "feedback": "Erreur : le `x = 200` dans `f` crée une\nvariable **locale**, qui ne modifie pas la\nglobale.\n"
            },
            {
              "text": "```\n200\n100\n```\n",
              "correct": true,
              "feedback": "Bonne réponse : `x` à l'intérieur de `f`\nest local et masque la globale. À l'extérieur,\nla globale `x` reste à 100.\n"
            },
            {
              "text": "Erreur",
              "correct": false,
              "feedback": "Erreur : aucune erreur.\n"
            }
          ],
          "explanation": "Cas typique d'**ombrage** (shadowing). Source\nde confusion fréquente. Pour éviter,\nprivilégier le passage en paramètre."
        }
      ]
    },
    {
      "id": "q22",
      "difficulty": 3,
      "skills": [
        "retour-conditionnel"
      ],
      "title": "Retours multiples",
      "partie": "parametres",
      "statement": "```python\ndef signe(x):\n    if x > 0:\n        return 1\n    if x < 0:\n        return -1\n    return 0\n```\nPourquoi ce code marche-t-il sans `elif` ?",
      "options": [
        {
          "text": "Parce que `return` quitte la fonction immédiatement",
          "correct": true,
          "feedback": "Bonne réponse : si `x > 0`, le premier\n`return 1` quitte la fonction et les tests\nsuivants ne sont jamais évalués. Pas besoin\nd'`elif`, le code est plus plat et lisible.\n"
        },
        {
          "text": "Parce que Python réordonne automatiquement les tests",
          "correct": false,
          "feedback": "Python n'a aucune capacité\nd'inférence sur l'intention\ndu code. Si chaque branche\nfonctionne correctement\nici, c'est uniquement parce\nque `return` quitte la\nfonction immédiatement.\n"
        },
        {
          "text": "Parce que des `if` successifs sont équivalents à des `elif`",
          "correct": false,
          "feedback": "Erreur : ils ne sont pas mutuellement\nexclusifs sans `return` (chaque `if`\nserait testé).\n"
        },
        {
          "text": "Parce qu'un `else` implicite termine chaque `if`",
          "correct": false,
          "feedback": "Erreur : il n'y a aucun `else`, explicite ou\nimplicite ; chaque `if` est testé tant\nqu'aucun `return` n'a été exécuté.\n"
        }
      ],
      "explanation": "Idiome « early return » : sortir tôt des cas\nparticuliers, simplifier la logique."
    },
    {
      "id": "q23",
      "difficulty": 3,
      "skills": [
        "portee",
        "mutable"
      ],
      "title": "Paramètre mutable",
      "partie": "portee",
      "statement": "```python\ndef ajouter(liste, x):\n    liste.append(x)\nma_liste = [1, 2]\najouter(ma_liste, 3)\nprint(ma_liste)\n```\nQue produit ce code ?",
      "options": [
        {
          "text": "`[3]`",
          "correct": false,
          "feedback": "Erreur : on **ajoute**, on ne remplace pas.\n"
        },
        {
          "text": "`[1, 2, 3]`",
          "correct": true,
          "feedback": "Bonne réponse : la fonction reçoit une\nréférence vers le **même objet** liste que\nl'appelant. Elle modifie donc directement\ncette liste, ce qui peut surprendre.\n"
        },
        {
          "text": "Erreur",
          "correct": false,
          "feedback": "Erreur : code valide.\n"
        },
        {
          "text": "`[1, 2]`",
          "correct": false,
          "feedback": "Erreur : la liste **est** modifiée par la\nfonction.\n"
        }
      ],
      "explanation": "En Python, lorsqu'on passe une variable à une\nfonction, on transmet une référence vers la\nmême valeur. Pour les types **mutables**\n(listes, dicts), les modifications dans la\nfonction affectent donc l'original. Pour les\n**immuables** (int, str, tuple), aucun effet\nde bord n'est possible.",
      "variants": [
        {
          "statement": "```python\ndef ajouter(liste, x):\n    liste.append(x)\nma_liste = [1, 2]\najouter(ma_liste, 3)\nprint(ma_liste)\n```\nQue produit ce code ?",
          "options": [
            {
              "text": "`[3]`",
              "correct": false,
              "feedback": "Erreur : on **ajoute**, on ne remplace pas.\n"
            },
            {
              "text": "`[1, 2, 3]`",
              "correct": true,
              "feedback": "Bonne réponse : la fonction reçoit une\nréférence vers le **même objet** liste que\nl'appelant. Elle modifie donc directement\ncette liste, ce qui peut surprendre.\n"
            },
            {
              "text": "Erreur",
              "correct": false,
              "feedback": "Erreur : code valide.\n"
            },
            {
              "text": "`[1, 2]`",
              "correct": false,
              "feedback": "Erreur : la liste **est** modifiée par la\nfonction.\n"
            }
          ],
          "explanation": "En Python, lorsqu'on passe une variable à une\nfonction, on transmet une référence vers la\nmême valeur. Pour les types **mutables**\n(listes, dicts), les modifications dans la\nfonction affectent donc l'original. Pour les\n**immuables** (int, str, tuple), aucun effet\nde bord n'est possible."
        },
        {
          "statement": "```python\ndef ajouter(liste, x):\n    liste.append(x)\nma_liste = [5, 8]\najouter(ma_liste, 1)\nprint(ma_liste)\n```\nQue produit ce code ?",
          "options": [
            {
              "text": "`[1]`",
              "correct": false,
              "feedback": "Erreur : on **ajoute**, on ne remplace pas.\n"
            },
            {
              "text": "`[5, 8, 1]`",
              "correct": true,
              "feedback": "Bonne réponse : la fonction reçoit une\nréférence vers le **même objet** liste que\nl'appelant. Elle modifie donc directement\ncette liste, ce qui peut surprendre.\n"
            },
            {
              "text": "Erreur",
              "correct": false,
              "feedback": "Erreur : code valide.\n"
            },
            {
              "text": "`[5, 8]`",
              "correct": false,
              "feedback": "Erreur : la liste **est** modifiée par la\nfonction.\n"
            }
          ],
          "explanation": "En Python, lorsqu'on passe une variable à une\nfonction, on transmet une référence vers la\nmême valeur. Pour les types **mutables**\n(listes, dicts), les modifications dans la\nfonction affectent donc l'original. Pour les\n**immuables** (int, str, tuple), aucun effet\nde bord n'est possible."
        },
        {
          "statement": "```python\ndef ajouter(liste, x):\n    liste.append(x)\nma_liste = [4, 4, 4]\najouter(ma_liste, 9)\nprint(ma_liste)\n```\nQue produit ce code ?",
          "options": [
            {
              "text": "`[9]`",
              "correct": false,
              "feedback": "Erreur : on **ajoute**, on ne remplace pas.\n"
            },
            {
              "text": "`[4, 4, 4, 9]`",
              "correct": true,
              "feedback": "Bonne réponse : la fonction reçoit une\nréférence vers le **même objet** liste que\nl'appelant. Elle modifie donc directement\ncette liste, ce qui peut surprendre.\n"
            },
            {
              "text": "Erreur",
              "correct": false,
              "feedback": "Erreur : code valide.\n"
            },
            {
              "text": "`[4, 4, 4]`",
              "correct": false,
              "feedback": "Erreur : la liste **est** modifiée par la\nfonction.\n"
            }
          ],
          "explanation": "En Python, lorsqu'on passe une variable à une\nfonction, on transmet une référence vers la\nmême valeur. Pour les types **mutables**\n(listes, dicts), les modifications dans la\nfonction affectent donc l'original. Pour les\n**immuables** (int, str, tuple), aucun effet\nde bord n'est possible."
        }
      ]
    },
    {
      "id": "q24",
      "difficulty": 3,
      "skills": [
        "return",
        "while",
        "trace"
      ],
      "title": "Une suite calculée appel après appel",
      "partie": "parametres",
      "statement": "```python\ndef suivant(n):\n    if n % 2 == 0:\n        return n // 2\n    return 3 * n + 1\nn = 6\netapes = 0\nwhile n != 1:\n    n = suivant(n)\n    etapes = etapes + 1\nprint(etapes)\n```\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "La boucle ne s'arrête jamais",
          "correct": false,
          "feedback": "Erreur : tu fais exécuter les deux `return` à chaque appel. Quand `n` est pair, `return n // 2` termine la fonction et la ligne suivante n'est pas atteinte ; la suite finit par valoir $1$.\n"
        },
        {
          "text": "$7$",
          "correct": false,
          "feedback": "Erreur : il manque un tour. Les valeurs successives sont 3, 10, 5, 16, 8, 4, 2, 1 : huit appels, et `etapes` augmente à chacun, y compris celui qui renvoie $1$.\n"
        },
        {
          "text": "$8$",
          "correct": true,
          "feedback": "Bonne réponse : `n` prend les valeurs 3, 10, 5, 16, 8, 4, 2, 1. Chaque appel ajoute une étape, soit huit, et la boucle s'arrête quand `n` vaut $1$.\n"
        },
        {
          "text": "$9$",
          "correct": false,
          "feedback": "Erreur : tu comptes aussi la valeur de départ $6$, mais `etapes` n'augmente qu'après un appel à `suivant`. Il y a huit appels avant d'atteindre $1$.\n"
        }
      ],
      "explanation": "Un `return` termine immédiatement l'exécution de la fonction : une seule des deux instructions `return` s'exécute à chaque appel. Pour dérouler une boucle qui appelle une fonction, on note la valeur renvoyée à chaque tour.",
      "variants": [
        {
          "statement": "```python\ndef suivant(n):\n    if n % 2 == 0:\n        return n // 2\n    return 3 * n + 1\nn = 6\netapes = 0\nwhile n != 1:\n    n = suivant(n)\n    etapes = etapes + 1\nprint(etapes)\n```\nQu'affiche ce programme ?",
          "options": [
            {
              "text": "La boucle ne s'arrête jamais",
              "correct": false,
              "feedback": "Erreur : tu fais exécuter les deux `return` à chaque appel. Quand `n` est pair, `return n // 2` termine la fonction et la ligne suivante n'est pas atteinte ; la suite finit par valoir $1$.\n"
            },
            {
              "text": "$7$",
              "correct": false,
              "feedback": "Erreur : il manque un tour. Les valeurs successives sont 3, 10, 5, 16, 8, 4, 2, 1 : huit appels, et `etapes` augmente à chacun, y compris celui qui renvoie $1$.\n"
            },
            {
              "text": "$8$",
              "correct": true,
              "feedback": "Bonne réponse : `n` prend les valeurs 3, 10, 5, 16, 8, 4, 2, 1. Chaque appel ajoute une étape, soit huit, et la boucle s'arrête quand `n` vaut $1$.\n"
            },
            {
              "text": "$9$",
              "correct": false,
              "feedback": "Erreur : tu comptes aussi la valeur de départ $6$, mais `etapes` n'augmente qu'après un appel à `suivant`. Il y a huit appels avant d'atteindre $1$.\n"
            }
          ],
          "explanation": "Un `return` termine immédiatement l'exécution de la fonction : une seule des deux instructions `return` s'exécute à chaque appel. Pour dérouler une boucle qui appelle une fonction, on note la valeur renvoyée à chaque tour."
        },
        {
          "statement": "```python\ndef suivant(n):\n    if n % 2 == 0:\n        return n // 2\n    return 3 * n + 1\nn = 7\netapes = 0\nwhile n != 1:\n    n = suivant(n)\n    etapes = etapes + 1\nprint(etapes)\n```\nQu'affiche ce programme ?",
          "options": [
            {
              "text": "La boucle ne s'arrête jamais",
              "correct": false,
              "feedback": "Erreur : tu fais exécuter les deux `return` à chaque appel. Quand `n` est pair, `return n // 2` termine la fonction et la ligne suivante n'est pas atteinte ; la suite finit par valoir $1$.\n"
            },
            {
              "text": "$15$",
              "correct": false,
              "feedback": "Erreur : il manque un tour. Les valeurs successives sont 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1 : seize appels, et `etapes` augmente à chacun, y compris celui qui renvoie $1$.\n"
            },
            {
              "text": "$16$",
              "correct": true,
              "feedback": "Bonne réponse : `n` prend les valeurs 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. Chaque appel ajoute une étape, soit seize, et la boucle s'arrête quand `n` vaut $1$.\n"
            },
            {
              "text": "$17$",
              "correct": false,
              "feedback": "Erreur : tu comptes aussi la valeur de départ $7$, mais `etapes` n'augmente qu'après un appel à `suivant`. Il y a seize appels avant d'atteindre $1$.\n"
            }
          ],
          "explanation": "Un `return` termine immédiatement l'exécution de la fonction : une seule des deux instructions `return` s'exécute à chaque appel. Pour dérouler une boucle qui appelle une fonction, on note la valeur renvoyée à chaque tour."
        },
        {
          "statement": "```python\ndef suivant(n):\n    if n % 2 == 0:\n        return n // 2\n    return 3 * n + 1\nn = 12\netapes = 0\nwhile n != 1:\n    n = suivant(n)\n    etapes = etapes + 1\nprint(etapes)\n```\nQu'affiche ce programme ?",
          "options": [
            {
              "text": "La boucle ne s'arrête jamais",
              "correct": false,
              "feedback": "Erreur : tu fais exécuter les deux `return` à chaque appel. Quand `n` est pair, `return n // 2` termine la fonction et la ligne suivante n'est pas atteinte ; la suite finit par valoir $1$.\n"
            },
            {
              "text": "$8$",
              "correct": false,
              "feedback": "Erreur : il manque un tour. Les valeurs successives sont 6, 3, 10, 5, 16, 8, 4, 2, 1 : neuf appels, et `etapes` augmente à chacun, y compris celui qui renvoie $1$.\n"
            },
            {
              "text": "$9$",
              "correct": true,
              "feedback": "Bonne réponse : `n` prend les valeurs 6, 3, 10, 5, 16, 8, 4, 2, 1. Chaque appel ajoute une étape, soit neuf, et la boucle s'arrête quand `n` vaut $1$.\n"
            },
            {
              "text": "$10$",
              "correct": false,
              "feedback": "Erreur : tu comptes aussi la valeur de départ $12$, mais `etapes` n'augmente qu'après un appel à `suivant`. Il y a neuf appels avant d'atteindre $1$.\n"
            }
          ],
          "explanation": "Un `return` termine immédiatement l'exécution de la fonction : une seule des deux instructions `return` s'exécute à chaque appel. Pour dérouler une boucle qui appelle une fonction, on note la valeur renvoyée à chaque tour."
        }
      ]
    },
    {
      "id": "q25",
      "difficulty": 3,
      "skills": [
        "synthese"
      ],
      "title": "Synthèse",
      "partie": "definition",
      "statement": "Parmi les affirmations suivantes sur les\nfonctions Python, laquelle est **fausse** ?",
      "options": [
        {
          "text": "Les fonctions Python peuvent être passées comme paramètres d'autres fonctions",
          "correct": false,
          "feedback": "Vrai : une fonction peut être transmise en argument à une autre fonction, comme la fonction clé passée à `sorted`.\n"
        },
        {
          "text": "On peut renvoyer plusieurs valeurs avec un tuple (ex. `return a, b`).",
          "correct": false,
          "feedback": "Vrai : idiome Python pour les retours\nmultiples.\n"
        },
        {
          "text": "Une fonction sans `return` renvoie implicitement `None`",
          "correct": false,
          "feedback": "Vrai : convention Python.\n"
        },
        {
          "text": "Les variables locales d'une fonction sont accessibles depuis l'extérieur",
          "correct": true,
          "feedback": "Faux (donc bonne réponse) : les variables\nlocales sont confinées à la fonction.\nC'est le principe de la **portée** (scope).\n"
        }
      ],
      "explanation": "Mnémonique : portée = « ce qui est défini\ndans une fonction reste dans la fonction »\n(sauf retour explicite)."
    },
    {
      "id": "q26",
      "difficulty": 2,
      "skills": [
        "composition",
        "evaluation"
      ],
      "title": "Composition d'appels de fonctions",
      "partie": "definition",
      "statement": "On considère le code suivant :\n```python\ndef carre(x):\n    return x * x\ndef incremente(x):\n    return x + 1\na = carre(incremente(3))\n```\nQuelle est la valeur de `a` après l'exécution ?",
      "options": [
        {
          "text": "$10$",
          "correct": false,
          "feedback": "Erreur : c'est `incremente(carre(3))`, l'ordre\ninversé : $9 + 1$. Or `incremente` est\nappliqué en premier, à $3$, ce qui donne $4$,\npuis `carre` calcule $4 \\times 4$.\n"
        },
        {
          "text": "$7$",
          "correct": false,
          "feedback": "Erreur : on a additionné $3$ et `incremente(3) = 4`.\nMais `carre` calcule un carré, pas une somme : la\nbonne opération est $4 \\times 4$.\n"
        },
        {
          "text": "$9$",
          "correct": false,
          "feedback": "Erreur : on a appliqué seulement `carre(3)`, sans\ntenir compte de `incremente`. Or `incremente`\nest appliqué en premier, à $3$, ce qui donne $4$.\n"
        },
        {
          "text": "$16$",
          "correct": true,
          "feedback": "Bonne réponse : Python évalue d'abord l'argument\nle plus interne, soit `incremente(3) = 4`, puis\napplique `carre` à ce résultat : $4 \\times 4 =\n16$.\n"
        }
      ],
      "explanation": "Pour évaluer une expression `f(g(x))`, Python\ncalcule d'abord `g(x)`, puis applique `f` à ce\nrésultat. Cette composition est l'un des moyens\nles plus simples de combiner des fonctions\nréutilisables, sans variables intermédiaires.",
      "variants": [
        {
          "statement": "On considère le code suivant :\n```python\ndef carre(x):\n    return x * x\ndef incremente(x):\n    return x + 1\na = carre(incremente(3))\n```\nQuelle est la valeur de `a` après l'exécution ?",
          "options": [
            {
              "text": "$10$",
              "correct": false,
              "feedback": "Erreur : c'est `incremente(carre(3))`, l'ordre\ninversé : $9 + 1$. Or `incremente` est\nappliqué en premier, à $3$, ce qui donne $4$,\npuis `carre` calcule $4 \\times 4$.\n"
            },
            {
              "text": "$7$",
              "correct": false,
              "feedback": "Erreur : on a additionné $3$ et `incremente(3) = 4`.\nMais `carre` calcule un carré, pas une somme : la\nbonne opération est $4 \\times 4$.\n"
            },
            {
              "text": "$9$",
              "correct": false,
              "feedback": "Erreur : on a appliqué seulement `carre(3)`, sans\ntenir compte de `incremente`. Or `incremente`\nest appliqué en premier, à $3$, ce qui donne $4$.\n"
            },
            {
              "text": "$16$",
              "correct": true,
              "feedback": "Bonne réponse : Python évalue d'abord l'argument\nle plus interne, soit `incremente(3) = 4`, puis\napplique `carre` à ce résultat : $4 \\times 4 =\n16$.\n"
            }
          ],
          "explanation": "Pour évaluer une expression `f(g(x))`, Python\ncalcule d'abord `g(x)`, puis applique `f` à ce\nrésultat. Cette composition est l'un des moyens\nles plus simples de combiner des fonctions\nréutilisables, sans variables intermédiaires."
        },
        {
          "statement": "On considère le code suivant :\n```python\ndef carre(x):\n    return x * x\ndef incremente(x):\n    return x + 1\na = carre(incremente(5))\n```\nQuelle est la valeur de `a` après l'exécution ?",
          "options": [
            {
              "text": "$26$",
              "correct": false,
              "feedback": "Erreur : c'est `incremente(carre(5))`, l'ordre\ninversé : $25 + 1$. Or `incremente` est\nappliqué en premier, à $5$, ce qui donne $6$,\npuis `carre` calcule $6 \\times 6$.\n"
            },
            {
              "text": "$11$",
              "correct": false,
              "feedback": "Erreur : on a additionné $5$ et `incremente(5) = 6`.\nMais `carre` calcule un carré, pas une somme : la\nbonne opération est $6 \\times 6$.\n"
            },
            {
              "text": "$25$",
              "correct": false,
              "feedback": "Erreur : on a appliqué seulement `carre(5)`, sans\ntenir compte de `incremente`. Or `incremente`\nest appliqué en premier, à $5$, ce qui donne $6$.\n"
            },
            {
              "text": "$36$",
              "correct": true,
              "feedback": "Bonne réponse : Python évalue d'abord l'argument\nle plus interne, soit `incremente(5) = 6`, puis\napplique `carre` à ce résultat : $6 \\times 6 =\n36$.\n"
            }
          ],
          "explanation": "Pour évaluer une expression `f(g(x))`, Python\ncalcule d'abord `g(x)`, puis applique `f` à ce\nrésultat. Cette composition est l'un des moyens\nles plus simples de combiner des fonctions\nréutilisables, sans variables intermédiaires."
        },
        {
          "statement": "On considère le code suivant :\n```python\ndef carre(x):\n    return x * x\ndef incremente(x):\n    return x + 1\na = carre(incremente(9))\n```\nQuelle est la valeur de `a` après l'exécution ?",
          "options": [
            {
              "text": "$82$",
              "correct": false,
              "feedback": "Erreur : c'est `incremente(carre(9))`, l'ordre\ninversé : $81 + 1$. Or `incremente` est\nappliqué en premier, à $9$, ce qui donne $10$,\npuis `carre` calcule $10 \\times 10$.\n"
            },
            {
              "text": "$19$",
              "correct": false,
              "feedback": "Erreur : on a additionné $9$ et `incremente(9) = 10`.\nMais `carre` calcule un carré, pas une somme : la\nbonne opération est $10 \\times 10$.\n"
            },
            {
              "text": "$81$",
              "correct": false,
              "feedback": "Erreur : on a appliqué seulement `carre(9)`, sans\ntenir compte de `incremente`. Or `incremente`\nest appliqué en premier, à $9$, ce qui donne $10$.\n"
            },
            {
              "text": "$100$",
              "correct": true,
              "feedback": "Bonne réponse : Python évalue d'abord l'argument\nle plus interne, soit `incremente(9) = 10`, puis\napplique `carre` à ce résultat : $10 \\times 10 =\n100$.\n"
            }
          ],
          "explanation": "Pour évaluer une expression `f(g(x))`, Python\ncalcule d'abord `g(x)`, puis applique `f` à ce\nrésultat. Cette composition est l'un des moyens\nles plus simples de combiner des fonctions\nréutilisables, sans variables intermédiaires."
        }
      ]
    },
    {
      "id": "q27",
      "difficulty": 2,
      "skills": [
        "annotations",
        "type-hint"
      ],
      "title": "Annotations de type",
      "partie": "definition",
      "statement": "On lit la signature suivante :\n\n```python\ndef aire(longueur: float, largeur: float) -> float:\n```\n\nQue signifie la flèche `->` et l'annotation `float`\nqui la suit ?",
      "options": [
        {
          "text": "Une annotation indiquant le type de retour attendu (flottant), sans vérification à l'exécution",
          "correct": true,
          "feedback": "Bonne réponse : la flèche introduit l'annotation du type renvoyé. Comme les annotations de paramètres, elle est facultative et purement informative : elle documente la fonction pour ses lecteurs.\n"
        },
        {
          "text": "Cette syntaxe est tout simplement invalide en Python",
          "correct": false,
          "feedback": "Erreur : les annotations de type sont parfaitement valides en Python. Elles servent à rendre le prototype d'une fonction plus lisible.\n"
        },
        {
          "text": "La flèche transforme le résultat en flottant avant de le renvoyer",
          "correct": false,
          "feedback": "Erreur : les annotations n'effectuent **aucune conversion**. La fonction renvoie strictement la\nvaleur retournée par son `return`, sans\nmodification.\n"
        },
        {
          "text": "La fonction renvoie obligatoirement un nombre flottant, sinon Python lève une exception",
          "correct": false,
          "feedback": "Erreur : Python ne vérifie pas les annotations à l'exécution. La fonction peut tout à fait renvoyer un autre type sans erreur. Les annotations servent uniquement à documenter le code.\n"
        }
      ],
      "explanation": "L'annotation `param: type` documente le type attendu d'un paramètre, l'annotation `-> type` documente celui de la valeur de retour. Ces indications n'ont aucun effet à l'exécution mais sont précieuses pour la lecture du code."
    },
    {
      "id": "q28",
      "difficulty": 3,
      "skills": [
        "portee",
        "effet-de-bord",
        "liste"
      ],
      "title": "Effet de bord sur une liste paramètre",
      "partie": "portee",
      "statement": "On exécute le code suivant :\n```python\ndef ajouter_zero(t):\n    t.append(0)\nma_liste = [1, 2, 3]\najouter_zero(ma_liste)\nprint(ma_liste)\n```\nQue va afficher `print` ?",
      "options": [
        {
          "text": "`[1, 2, 3, 0]`",
          "correct": true,
          "feedback": "Bonne réponse : `t` et `ma_liste` désignent le\n**même objet liste** en mémoire. La méthode\n`append` modifie cet objet ; après l'appel,\n`ma_liste` reflète donc le changement.\n"
        },
        {
          "text": "Le code lève une erreur car `t` n'est pas connu en dehors de la fonction",
          "correct": false,
          "feedback": "Erreur : `t` n'est utilisé qu'à l'intérieur de\nla fonction, mais la liste qu'il référence\ncontinue d'exister à l'extérieur. Python passe\nles paramètres par **référence d'objet**.\n"
        },
        {
          "text": "`[1, 2, 3]`",
          "correct": false,
          "feedback": "Erreur : la fonction modifie effectivement la\nliste passée en paramètre. La méthode `append`\nagit sur l'objet partagé entre l'appelant et la\nfonction, donc la modification est visible à\nl'extérieur.\n"
        },
        {
          "text": "`[0, 1, 2, 3]`",
          "correct": false,
          "feedback": "Erreur : `append` ajoute en fin de liste, pas\nen début. Placer un 0 en tête demanderait de\nconstruire une nouvelle liste, `[0] + t`, puis\nde la renvoyer avec `return`.\n"
        }
      ],
      "explanation": "Quand un paramètre est un objet **mutable** (liste,\ndictionnaire), une fonction peut le\nmodifier en place sans avoir à le renvoyer. C'est un\neffet de bord, à utiliser avec parcimonie : il rend\nle comportement moins prévisible et complique la\nlecture du code.",
      "variants": [
        {
          "statement": "On exécute le code suivant :\n```python\ndef ajouter_zero(t):\n    t.append(0)\nma_liste = [1, 2, 3]\najouter_zero(ma_liste)\nprint(ma_liste)\n```\nQue va afficher `print` ?",
          "options": [
            {
              "text": "`[1, 2, 3, 0]`",
              "correct": true,
              "feedback": "Bonne réponse : `t` et `ma_liste` désignent le\n**même objet liste** en mémoire. La méthode\n`append` modifie cet objet ; après l'appel,\n`ma_liste` reflète donc le changement.\n"
            },
            {
              "text": "Le code lève une erreur car `t` n'est pas connu en dehors de la fonction",
              "correct": false,
              "feedback": "Erreur : `t` n'est utilisé qu'à l'intérieur de\nla fonction, mais la liste qu'il référence\ncontinue d'exister à l'extérieur. Python passe\nles paramètres par **référence d'objet**.\n"
            },
            {
              "text": "`[1, 2, 3]`",
              "correct": false,
              "feedback": "Erreur : la fonction modifie effectivement la\nliste passée en paramètre. La méthode `append`\nagit sur l'objet partagé entre l'appelant et la\nfonction, donc la modification est visible à\nl'extérieur.\n"
            },
            {
              "text": "`[0, 1, 2, 3]`",
              "correct": false,
              "feedback": "Erreur : `append` ajoute en fin de liste, pas\nen début. Placer un 0 en tête demanderait de\nconstruire une nouvelle liste, `[0] + t`, puis\nde la renvoyer avec `return`.\n"
            }
          ],
          "explanation": "Quand un paramètre est un objet **mutable** (liste,\ndictionnaire), une fonction peut le\nmodifier en place sans avoir à le renvoyer. C'est un\neffet de bord, à utiliser avec parcimonie : il rend\nle comportement moins prévisible et complique la\nlecture du code."
        },
        {
          "statement": "On exécute le code suivant :\n```python\ndef ajouter_zero(t):\n    t.append(0)\nma_liste = [7, 8]\najouter_zero(ma_liste)\nprint(ma_liste)\n```\nQue va afficher `print` ?",
          "options": [
            {
              "text": "`[7, 8, 0]`",
              "correct": true,
              "feedback": "Bonne réponse : `t` et `ma_liste` désignent le\n**même objet liste** en mémoire. La méthode\n`append` modifie cet objet ; après l'appel,\n`ma_liste` reflète donc le changement.\n"
            },
            {
              "text": "Le code lève une erreur car `t` n'est pas connu en dehors de la fonction",
              "correct": false,
              "feedback": "Erreur : `t` n'est utilisé qu'à l'intérieur de\nla fonction, mais la liste qu'il référence\ncontinue d'exister à l'extérieur. Python passe\nles paramètres par **référence d'objet**.\n"
            },
            {
              "text": "`[7, 8]`",
              "correct": false,
              "feedback": "Erreur : la fonction modifie effectivement la\nliste passée en paramètre. La méthode `append`\nagit sur l'objet partagé entre l'appelant et la\nfonction, donc la modification est visible à\nl'extérieur.\n"
            },
            {
              "text": "`[0, 7, 8]`",
              "correct": false,
              "feedback": "Erreur : `append` ajoute en fin de liste, pas\nen début. Placer un 0 en tête demanderait de\nconstruire une nouvelle liste, `[0] + t`, puis\nde la renvoyer avec `return`.\n"
            }
          ],
          "explanation": "Quand un paramètre est un objet **mutable** (liste,\ndictionnaire), une fonction peut le\nmodifier en place sans avoir à le renvoyer. C'est un\neffet de bord, à utiliser avec parcimonie : il rend\nle comportement moins prévisible et complique la\nlecture du code."
        },
        {
          "statement": "On exécute le code suivant :\n```python\ndef ajouter_zero(t):\n    t.append(0)\nma_liste = [10, 20, 30, 40]\najouter_zero(ma_liste)\nprint(ma_liste)\n```\nQue va afficher `print` ?",
          "options": [
            {
              "text": "`[10, 20, 30, 40, 0]`",
              "correct": true,
              "feedback": "Bonne réponse : `t` et `ma_liste` désignent le\n**même objet liste** en mémoire. La méthode\n`append` modifie cet objet ; après l'appel,\n`ma_liste` reflète donc le changement.\n"
            },
            {
              "text": "Le code lève une erreur car `t` n'est pas connu en dehors de la fonction",
              "correct": false,
              "feedback": "Erreur : `t` n'est utilisé qu'à l'intérieur de\nla fonction, mais la liste qu'il référence\ncontinue d'exister à l'extérieur. Python passe\nles paramètres par **référence d'objet**.\n"
            },
            {
              "text": "`[10, 20, 30, 40]`",
              "correct": false,
              "feedback": "Erreur : la fonction modifie effectivement la\nliste passée en paramètre. La méthode `append`\nagit sur l'objet partagé entre l'appelant et la\nfonction, donc la modification est visible à\nl'extérieur.\n"
            },
            {
              "text": "`[0, 10, 20, 30, 40]`",
              "correct": false,
              "feedback": "Erreur : `append` ajoute en fin de liste, pas\nen début. Placer un 0 en tête demanderait de\nconstruire une nouvelle liste, `[0] + t`, puis\nde la renvoyer avec `return`.\n"
            }
          ],
          "explanation": "Quand un paramètre est un objet **mutable** (liste,\ndictionnaire), une fonction peut le\nmodifier en place sans avoir à le renvoyer. C'est un\neffet de bord, à utiliser avec parcimonie : il rend\nle comportement moins prévisible et complique la\nlecture du code."
        }
      ]
    },
    {
      "id": "q29",
      "difficulty": 2,
      "skills": [
        "predicat",
        "booleen"
      ],
      "title": "Fonction prédicat",
      "partie": "parametres",
      "statement": "On souhaite écrire une fonction `est_pair(n)` qui\nrenvoie `True` si l'entier `n` est pair, `False`\nsinon. Quelle écriture est la plus claire et la plus\nidiomatique ?",
      "options": [
        {
          "text": "```python\ndef est_pair(n):\n    if n % 2 == 0:\n        return True\n    else:\n        return False\n```\n",
          "correct": false,
          "feedback": "Code correct mais redondant : on construit un\nbooléen à partir d'un test booléen. Préférer\n`return n % 2 == 0`, qui exprime directement\nl'idée.\n"
        },
        {
          "text": "```python\ndef est_pair(n):\n    return n % 2 == 0\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : on renvoie directement la\nvaleur du test booléen, sans passer par un\n`if`. C'est plus court, plus lisible, et c'est\nl'idiome Python pour ce qu'on appelle un\n**prédicat**.\n"
        },
        {
          "text": "```python\ndef est_pair(n):\n    return n / 2\n```\n",
          "correct": false,
          "feedback": "Erreur : la division `n / 2` renvoie un\nflottant (par exemple $1{,}5$ ou $2{,}0$),\npas un booléen. Pour tester la parité, il faut\nutiliser le **reste** (modulo `%`), pas le\nquotient.\n"
        },
        {
          "text": "```python\ndef est_pair(n):\n    print(n % 2 == 0)\n```\n",
          "correct": false,
          "feedback": "Erreur : la fonction ne renvoie rien (elle\nrenvoie `None`). Elle ne peut donc pas être\nutilisée dans un test comme\n`if est_pair(x):`. Préférer `return` plutôt\nque `print`.\n"
        }
      ],
      "explanation": "Une fonction qui renvoie `True` ou `False` est\nappelée **prédicat**. Convention : nommer ces\nfonctions avec un préfixe `est_`, `a_`, `verifie_`\nou similaire, pour signaler immédiatement qu'elles\nrenvoient un booléen."
    },
    {
      "id": "q30",
      "difficulty": 2,
      "skills": [
        "portee",
        "variable-globale",
        "lecture"
      ],
      "title": "Une variable globale lue dans une fonction",
      "partie": "portee",
      "statement": "Qu'affiche ce programme ?\n```python\ntaux = 0.2\n\ndef ttc(prix):\n    return prix * (1 + taux)\n\nprint(ttc(100))\n```",
      "options": [
        {
          "text": "`120.0`",
          "correct": true,
          "feedback": "Bonne réponse : une fonction peut lire une variable globale sans\ndéclaration particulière. `taux` vaut $0{,}2$, d'où\n$100 \\times 1{,}2$.\n"
        },
        {
          "text": "Une erreur, `taux` n'étant pas défini dans la fonction",
          "correct": false,
          "feedback": "Erreur : une variable globale est visible dans les fonctions ;\nseule sa modification demanderait une déclaration particulière.\n"
        },
        {
          "text": "`100`",
          "correct": false,
          "feedback": "Erreur : le taux est bien appliqué, le prix est majoré.\n"
        },
        {
          "text": "`20.0`",
          "correct": false,
          "feedback": "Erreur : $20.0$ est le montant de la taxe seule, pas le prix\nmajoré.\n"
        }
      ],
      "explanation": "Lire une variable globale dans une fonction est permis et\ncourant pour des constantes ; la modifier demande une déclaration\nexplicite et reste à éviter.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\ntaux = 0.2\n\ndef ttc(prix):\n    return prix * (1 + taux)\n\nprint(ttc(100))\n```",
          "options": [
            {
              "text": "`120.0`",
              "correct": true,
              "feedback": "Bonne réponse : une fonction peut lire une variable globale sans\ndéclaration particulière. `taux` vaut $0{,}2$, d'où\n$100 \\times 1{,}2$.\n"
            },
            {
              "text": "Une erreur, `taux` n'étant pas défini dans la fonction",
              "correct": false,
              "feedback": "Erreur : une variable globale est visible dans les fonctions ;\nseule sa modification demanderait une déclaration particulière.\n"
            },
            {
              "text": "`100`",
              "correct": false,
              "feedback": "Erreur : le taux est bien appliqué, le prix est majoré.\n"
            },
            {
              "text": "`20.0`",
              "correct": false,
              "feedback": "Erreur : $20.0$ est le montant de la taxe seule, pas le prix\nmajoré.\n"
            }
          ],
          "explanation": "Lire une variable globale dans une fonction est permis et\ncourant pour des constantes ; la modifier demande une déclaration\nexplicite et reste à éviter."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ntaux = 0.2\n\ndef ttc(prix):\n    return prix * (1 + taux)\n\nprint(ttc(50))\n```",
          "options": [
            {
              "text": "`60.0`",
              "correct": true,
              "feedback": "Bonne réponse : une fonction peut lire une variable globale sans\ndéclaration particulière. `taux` vaut $0{,}2$, d'où\n$50 \\times 1{,}2$.\n"
            },
            {
              "text": "Une erreur, `taux` n'étant pas défini dans la fonction",
              "correct": false,
              "feedback": "Erreur : une variable globale est visible dans les fonctions ;\nseule sa modification demanderait une déclaration particulière.\n"
            },
            {
              "text": "`50`",
              "correct": false,
              "feedback": "Erreur : le taux est bien appliqué, le prix est majoré.\n"
            },
            {
              "text": "`10.0`",
              "correct": false,
              "feedback": "Erreur : $10.0$ est le montant de la taxe seule, pas le prix\nmajoré.\n"
            }
          ],
          "explanation": "Lire une variable globale dans une fonction est permis et\ncourant pour des constantes ; la modifier demande une déclaration\nexplicite et reste à éviter."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ntaux = 0.2\n\ndef ttc(prix):\n    return prix * (1 + taux)\n\nprint(ttc(200))\n```",
          "options": [
            {
              "text": "`240.0`",
              "correct": true,
              "feedback": "Bonne réponse : une fonction peut lire une variable globale sans\ndéclaration particulière. `taux` vaut $0{,}2$, d'où\n$200 \\times 1{,}2$.\n"
            },
            {
              "text": "Une erreur, `taux` n'étant pas défini dans la fonction",
              "correct": false,
              "feedback": "Erreur : une variable globale est visible dans les fonctions ;\nseule sa modification demanderait une déclaration particulière.\n"
            },
            {
              "text": "`200`",
              "correct": false,
              "feedback": "Erreur : le taux est bien appliqué, le prix est majoré.\n"
            },
            {
              "text": "`40.0`",
              "correct": false,
              "feedback": "Erreur : $40.0$ est le montant de la taxe seule, pas le prix\nmajoré.\n"
            }
          ],
          "explanation": "Lire une variable globale dans une fonction est permis et\ncourant pour des constantes ; la modifier demande une déclaration\nexplicite et reste à éviter."
        }
      ]
    },
    {
      "id": "q31",
      "difficulty": 1,
      "skills": [
        "portee",
        "variable-locale",
        "duree-de-vie"
      ],
      "title": "La durée de vie d'une variable locale",
      "partie": "portee",
      "statement": "Une variable créée à l'intérieur d'une fonction existe pendant\ncombien de temps ?",
      "options": [
        {
          "text": "Le temps de l'appel, jusqu'au retour de la fonction",
          "correct": true,
          "feedback": "Bonne réponse : chaque appel crée ses variables locales et les\ndétruit en se terminant. Deux appels successifs ne partagent\nrien.\n"
        },
        {
          "text": "Jusqu'à la fin du programme, comme une variable globale",
          "correct": false,
          "feedback": "Erreur : seules les variables globales vivent jusqu'à la fin du\nprogramme.\n"
        },
        {
          "text": "Jusqu'au prochain appel de la même fonction",
          "correct": false,
          "feedback": "Erreur : le prochain appel repart de zéro, sans trace du\nprécédent.\n"
        },
        {
          "text": "Le temps d'une seule instruction, puis elle disparaît",
          "correct": false,
          "feedback": "Erreur : la variable reste disponible dans toute la suite de la\nfonction.\n"
        }
      ],
      "explanation": "Les variables locales naissent et meurent avec l'appel : c'est ce\nqui rend une fonction indépendante de ce qui se passe ailleurs."
    },
    {
      "id": "q32",
      "difficulty": 2,
      "skills": [
        "liste",
        "copie",
        "effet-de-bord"
      ],
      "title": "Une fonction qui construit une nouvelle liste",
      "partie": "portee",
      "statement": "Qu'affiche ce programme ?\n```python\ndef doubles(t):\n    r = []\n    for x in t:\n        r.append(2 * x)\n    return r\n\nnotes = [5, 8]\nd = doubles(notes)\nprint(notes, d)\n```",
      "options": [
        {
          "text": "`[5, 8] [10, 16]`",
          "correct": true,
          "feedback": "Bonne réponse : la fonction remplit une liste neuve `r` et la\nrenvoie. La liste `notes` passée en argument n'est jamais\nmodifiée.\n"
        },
        {
          "text": "`[10, 16] [10, 16]`",
          "correct": false,
          "feedback": "Erreur : `t` n'est pas modifiée ; seules des lectures sont\nfaites sur elle.\n"
        },
        {
          "text": "`[5, 8] [5, 8]`",
          "correct": false,
          "feedback": "Erreur : `d` reçoit la liste renvoyée, dont les éléments sont\ndoublés.\n"
        },
        {
          "text": "Une erreur, `r` n'existant pas en dehors de la fonction",
          "correct": false,
          "feedback": "Erreur : `r` est renvoyée par `return` et rangée dans `d` ; son\nnom local importe peu.\n"
        }
      ],
      "explanation": "Construire et renvoyer une nouvelle liste évite tout effet de bord\nsur l'argument : l'appelant garde sa liste intacte."
    },
    {
      "id": "q33",
      "difficulty": 3,
      "skills": [
        "portee",
        "variable-de-boucle"
      ],
      "title": "La variable de boucle après la boucle",
      "partie": "portee",
      "statement": "Qu'affiche ce programme ?\n```python\ndef compte():\n    for i in range(3):\n        x = i * 2\n    return i\n\nprint(compte())\n```",
      "options": [
        {
          "text": "`2`",
          "correct": true,
          "feedback": "Bonne réponse : en Python, la variable de boucle survit à la\nboucle et garde sa dernière valeur, ici $3 - 1$.\n"
        },
        {
          "text": "`3`",
          "correct": false,
          "feedback": "Erreur : `range(3)` s'arrête à $3 - 1$, valeur que `i`\nconserve.\n"
        },
        {
          "text": "Une erreur, `i` n'existant plus après la boucle",
          "correct": false,
          "feedback": "Erreur : contrairement à d'autres langages, Python ne supprime\npas la variable de boucle à la sortie.\n"
        },
        {
          "text": "`0`",
          "correct": false,
          "feedback": "Erreur : `i` a été réaffectée à chaque tour, sa dernière valeur\nest $3 - 1$.\n"
        }
      ],
      "explanation": "La variable de boucle est une variable locale ordinaire de la\nfonction : elle reste accessible après la boucle, avec sa dernière\nvaleur.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef compte():\n    for i in range(3):\n        x = i * 2\n    return i\n\nprint(compte())\n```",
          "options": [
            {
              "text": "`2`",
              "correct": true,
              "feedback": "Bonne réponse : en Python, la variable de boucle survit à la\nboucle et garde sa dernière valeur, ici $3 - 1$.\n"
            },
            {
              "text": "`3`",
              "correct": false,
              "feedback": "Erreur : `range(3)` s'arrête à $3 - 1$, valeur que `i`\nconserve.\n"
            },
            {
              "text": "Une erreur, `i` n'existant plus après la boucle",
              "correct": false,
              "feedback": "Erreur : contrairement à d'autres langages, Python ne supprime\npas la variable de boucle à la sortie.\n"
            },
            {
              "text": "`0`",
              "correct": false,
              "feedback": "Erreur : `i` a été réaffectée à chaque tour, sa dernière valeur\nest $3 - 1$.\n"
            }
          ],
          "explanation": "La variable de boucle est une variable locale ordinaire de la\nfonction : elle reste accessible après la boucle, avec sa dernière\nvaleur."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef compte():\n    for i in range(5):\n        x = i * 2\n    return i\n\nprint(compte())\n```",
          "options": [
            {
              "text": "`4`",
              "correct": true,
              "feedback": "Bonne réponse : en Python, la variable de boucle survit à la\nboucle et garde sa dernière valeur, ici $5 - 1$.\n"
            },
            {
              "text": "`5`",
              "correct": false,
              "feedback": "Erreur : `range(5)` s'arrête à $5 - 1$, valeur que `i`\nconserve.\n"
            },
            {
              "text": "Une erreur, `i` n'existant plus après la boucle",
              "correct": false,
              "feedback": "Erreur : contrairement à d'autres langages, Python ne supprime\npas la variable de boucle à la sortie.\n"
            },
            {
              "text": "`0`",
              "correct": false,
              "feedback": "Erreur : `i` a été réaffectée à chaque tour, sa dernière valeur\nest $5 - 1$.\n"
            }
          ],
          "explanation": "La variable de boucle est une variable locale ordinaire de la\nfonction : elle reste accessible après la boucle, avec sa dernière\nvaleur."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef compte():\n    for i in range(8):\n        x = i * 2\n    return i\n\nprint(compte())\n```",
          "options": [
            {
              "text": "`7`",
              "correct": true,
              "feedback": "Bonne réponse : en Python, la variable de boucle survit à la\nboucle et garde sa dernière valeur, ici $8 - 1$.\n"
            },
            {
              "text": "`8`",
              "correct": false,
              "feedback": "Erreur : `range(8)` s'arrête à $8 - 1$, valeur que `i`\nconserve.\n"
            },
            {
              "text": "Une erreur, `i` n'existant plus après la boucle",
              "correct": false,
              "feedback": "Erreur : contrairement à d'autres langages, Python ne supprime\npas la variable de boucle à la sortie.\n"
            },
            {
              "text": "`0`",
              "correct": false,
              "feedback": "Erreur : `i` a été réaffectée à chaque tour, sa dernière valeur\nest $8 - 1$.\n"
            }
          ],
          "explanation": "La variable de boucle est une variable locale ordinaire de la\nfonction : elle reste accessible après la boucle, avec sa dernière\nvaleur."
        }
      ]
    },
    {
      "id": "q34",
      "difficulty": 1,
      "skills": [
        "definition",
        "ordre",
        "appel"
      ],
      "title": "Un appel placé avant la définition",
      "partie": "definition",
      "statement": "Que produit ce programme ?\n```python\nprint(aire(3))\n\ndef aire(c):\n    return c * c\n```",
      "options": [
        {
          "text": "Une erreur, `aire` n'étant pas encore définie",
          "correct": true,
          "feedback": "Bonne réponse : Python exécute le fichier de haut en bas ; à la\npremière ligne, le nom `aire` est inconnu.\n"
        },
        {
          "text": "`9`, la définition étant lue avant l'exécution",
          "correct": false,
          "feedback": "Erreur : ce serait le résultat si la définition précédait\nl'appel.\n"
        },
        {
          "text": "`3`, l'argument étant affiché faute de fonction",
          "correct": false,
          "feedback": "Erreur : rien n'est affiché, le programme s'arrête sur l'appel.\n"
        },
        {
          "text": "Rien, la définition étant lue en premier par Python",
          "correct": false,
          "feedback": "Erreur : Python ne lit pas les définitions à l'avance ; `def`\nest une instruction comme une autre.\n"
        }
      ],
      "explanation": "Les définitions de fonctions se placent avant leur premier appel,\nen pratique en tête du programme."
    },
    {
      "id": "q35",
      "difficulty": 3,
      "skills": [
        "definition",
        "ordre",
        "appel-interne"
      ],
      "title": "Une fonction qui en appelle une autre définie plus bas",
      "partie": "definition",
      "statement": "Que produit ce programme ?\n```python\ndef a():\n    return b() + 1\n\ndef b():\n    return 2\n\nprint(a())\n```",
      "options": [
        {
          "text": "`3`, car `b` est définie avant que `a` ne soit appelée",
          "correct": true,
          "feedback": "Bonne réponse : le corps de `a` n'est exécuté qu'au moment de\nl'appel `a()`, après la définition de `b`. Le nom `b` est alors\nconnu.\n"
        },
        {
          "text": "Une erreur, `b` n'étant pas définie quand `a` est définie",
          "correct": false,
          "feedback": "Erreur : définir `a` ne vérifie pas l'existence de `b` ; seul\nl'appel la demande.\n"
        },
        {
          "text": "`1`, `b()` valant `None` faute de `return`",
          "correct": false,
          "feedback": "Erreur : `b` renvoie `2` grâce à son `return`.\n"
        },
        {
          "text": "`2`, `a` renvoyant directement le résultat de `b`",
          "correct": false,
          "feedback": "Erreur : `a` ajoute $1$ au résultat de `b`.\n"
        }
      ],
      "explanation": "L'ordre qui compte est celui des exécutions : une fonction peut\nmentionner une autre fonction définie plus bas, tant que l'appel a\nlieu après les deux définitions."
    },
    {
      "id": "q36",
      "difficulty": 2,
      "skills": [
        "parametre-par-defaut",
        "trace"
      ],
      "title": "Avec ou sans le second argument",
      "partie": "parametres",
      "statement": "Qu'affiche ce programme ?\n```python\ndef prix_ttc(ht, taux=0.2):\n    return ht * (1 + taux)\n\nprint(prix_ttc(100))\nprint(prix_ttc(100, 0.055))\n```",
      "options": [
        {
          "text": "`120.0` puis `105.5`",
          "correct": true,
          "feedback": "Bonne réponse : sans second argument, `taux` prend sa valeur par\ndéfaut $0{,}2$ ; avec `0.055`, cette valeur remplace le défaut.\n"
        },
        {
          "text": "`120.0` puis `120.0`",
          "correct": false,
          "feedback": "Erreur : le second appel fournit un taux, qui remplace la\nvaleur par défaut.\n"
        },
        {
          "text": "`105.5` puis `105.5`",
          "correct": false,
          "feedback": "Erreur : le premier appel ne donne pas de taux, le défaut\n$0{,}2$ s'applique.\n"
        },
        {
          "text": "Une erreur au premier appel, un argument manquant",
          "correct": false,
          "feedback": "Erreur : un paramètre avec valeur par défaut peut être omis à\nl'appel.\n"
        }
      ],
      "explanation": "Une valeur par défaut rend un paramètre facultatif ; l'argument\nfourni à l'appel a toujours priorité sur elle.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef prix_ttc(ht, taux=0.2):\n    return ht * (1 + taux)\n\nprint(prix_ttc(100))\nprint(prix_ttc(100, 0.055))\n```",
          "options": [
            {
              "text": "`120.0` puis `105.5`",
              "correct": true,
              "feedback": "Bonne réponse : sans second argument, `taux` prend sa valeur par\ndéfaut $0{,}2$ ; avec `0.055`, cette valeur remplace le défaut.\n"
            },
            {
              "text": "`120.0` puis `120.0`",
              "correct": false,
              "feedback": "Erreur : le second appel fournit un taux, qui remplace la\nvaleur par défaut.\n"
            },
            {
              "text": "`105.5` puis `105.5`",
              "correct": false,
              "feedback": "Erreur : le premier appel ne donne pas de taux, le défaut\n$0{,}2$ s'applique.\n"
            },
            {
              "text": "Une erreur au premier appel, un argument manquant",
              "correct": false,
              "feedback": "Erreur : un paramètre avec valeur par défaut peut être omis à\nl'appel.\n"
            }
          ],
          "explanation": "Une valeur par défaut rend un paramètre facultatif ; l'argument\nfourni à l'appel a toujours priorité sur elle."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef prix_ttc(ht, taux=0.2):\n    return ht * (1 + taux)\n\nprint(prix_ttc(50))\nprint(prix_ttc(50, 0.1))\n```",
          "options": [
            {
              "text": "`60.0` puis `55.0`",
              "correct": true,
              "feedback": "Bonne réponse : sans second argument, `taux` prend sa valeur par\ndéfaut $0{,}2$ ; avec `0.1`, cette valeur remplace le défaut.\n"
            },
            {
              "text": "`60.0` puis `60.0`",
              "correct": false,
              "feedback": "Erreur : le second appel fournit un taux, qui remplace la\nvaleur par défaut.\n"
            },
            {
              "text": "`55.0` puis `55.0`",
              "correct": false,
              "feedback": "Erreur : le premier appel ne donne pas de taux, le défaut\n$0{,}2$ s'applique.\n"
            },
            {
              "text": "Une erreur au premier appel, un argument manquant",
              "correct": false,
              "feedback": "Erreur : un paramètre avec valeur par défaut peut être omis à\nl'appel.\n"
            }
          ],
          "explanation": "Une valeur par défaut rend un paramètre facultatif ; l'argument\nfourni à l'appel a toujours priorité sur elle."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef prix_ttc(ht, taux=0.2):\n    return ht * (1 + taux)\n\nprint(prix_ttc(200))\nprint(prix_ttc(200, 0.0))\n```",
          "options": [
            {
              "text": "`240.0` puis `200.0`",
              "correct": true,
              "feedback": "Bonne réponse : sans second argument, `taux` prend sa valeur par\ndéfaut $0{,}2$ ; avec `0.0`, cette valeur remplace le défaut.\n"
            },
            {
              "text": "`240.0` puis `240.0`",
              "correct": false,
              "feedback": "Erreur : le second appel fournit un taux, qui remplace la\nvaleur par défaut.\n"
            },
            {
              "text": "`200.0` puis `200.0`",
              "correct": false,
              "feedback": "Erreur : le premier appel ne donne pas de taux, le défaut\n$0{,}2$ s'applique.\n"
            },
            {
              "text": "Une erreur au premier appel, un argument manquant",
              "correct": false,
              "feedback": "Erreur : un paramètre avec valeur par défaut peut être omis à\nl'appel.\n"
            }
          ],
          "explanation": "Une valeur par défaut rend un paramètre facultatif ; l'argument\nfourni à l'appel a toujours priorité sur elle."
        }
      ]
    },
    {
      "id": "q37",
      "difficulty": 3,
      "skills": [
        "parametre",
        "argument",
        "entier",
        "trace"
      ],
      "title": "Un paramètre modifié, un argument intact",
      "partie": "parametres",
      "statement": "Qu'affiche ce programme ?\n```python\ndef incremente(n):\n    n = n + 1\n    return n\n\nx = 5\nincremente(x)\nprint(x)\n```",
      "options": [
        {
          "text": "`5`",
          "correct": true,
          "feedback": "Bonne réponse : `n` est une variable locale qui reçoit une copie\nde la valeur de `x`. La modifier ne touche pas `x`, et la valeur\nrenvoyée n'est rangée nulle part.\n"
        },
        {
          "text": "`6`",
          "correct": false,
          "feedback": "Erreur : pour obtenir 6 dans `x`, il faudrait écrire\n`x = incremente(x)`.\n"
        },
        {
          "text": "`n`",
          "correct": false,
          "feedback": "Erreur : `print(x)` affiche la valeur de `x`, pas un nom.\n"
        },
        {
          "text": "Une erreur, `n` étant inconnu en dehors de la fonction",
          "correct": false,
          "feedback": "Erreur : le programme n'utilise `n` qu'à l'intérieur de la\nfonction, aucune erreur n'a lieu.\n"
        }
      ],
      "explanation": "Un entier passé en argument est copié dans le paramètre. Pour\nconserver le résultat, on récupère la valeur renvoyée.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef incremente(n):\n    n = n + 1\n    return n\n\nx = 5\nincremente(x)\nprint(x)\n```",
          "options": [
            {
              "text": "`5`",
              "correct": true,
              "feedback": "Bonne réponse : `n` est une variable locale qui reçoit une copie\nde la valeur de `x`. La modifier ne touche pas `x`, et la valeur\nrenvoyée n'est rangée nulle part.\n"
            },
            {
              "text": "`6`",
              "correct": false,
              "feedback": "Erreur : pour obtenir 6 dans `x`, il faudrait écrire\n`x = incremente(x)`.\n"
            },
            {
              "text": "`n`",
              "correct": false,
              "feedback": "Erreur : `print(x)` affiche la valeur de `x`, pas un nom.\n"
            },
            {
              "text": "Une erreur, `n` étant inconnu en dehors de la fonction",
              "correct": false,
              "feedback": "Erreur : le programme n'utilise `n` qu'à l'intérieur de la\nfonction, aucune erreur n'a lieu.\n"
            }
          ],
          "explanation": "Un entier passé en argument est copié dans le paramètre. Pour\nconserver le résultat, on récupère la valeur renvoyée."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef incremente(n):\n    n = n + 1\n    return n\n\nx = 12\nincremente(x)\nprint(x)\n```",
          "options": [
            {
              "text": "`12`",
              "correct": true,
              "feedback": "Bonne réponse : `n` est une variable locale qui reçoit une copie\nde la valeur de `x`. La modifier ne touche pas `x`, et la valeur\nrenvoyée n'est rangée nulle part.\n"
            },
            {
              "text": "`13`",
              "correct": false,
              "feedback": "Erreur : pour obtenir 13 dans `x`, il faudrait écrire\n`x = incremente(x)`.\n"
            },
            {
              "text": "`n`",
              "correct": false,
              "feedback": "Erreur : `print(x)` affiche la valeur de `x`, pas un nom.\n"
            },
            {
              "text": "Une erreur, `n` étant inconnu en dehors de la fonction",
              "correct": false,
              "feedback": "Erreur : le programme n'utilise `n` qu'à l'intérieur de la\nfonction, aucune erreur n'a lieu.\n"
            }
          ],
          "explanation": "Un entier passé en argument est copié dans le paramètre. Pour\nconserver le résultat, on récupère la valeur renvoyée."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef incremente(n):\n    n = n + 1\n    return n\n\nx = 40\nincremente(x)\nprint(x)\n```",
          "options": [
            {
              "text": "`40`",
              "correct": true,
              "feedback": "Bonne réponse : `n` est une variable locale qui reçoit une copie\nde la valeur de `x`. La modifier ne touche pas `x`, et la valeur\nrenvoyée n'est rangée nulle part.\n"
            },
            {
              "text": "`41`",
              "correct": false,
              "feedback": "Erreur : pour obtenir 41 dans `x`, il faudrait écrire\n`x = incremente(x)`.\n"
            },
            {
              "text": "`n`",
              "correct": false,
              "feedback": "Erreur : `print(x)` affiche la valeur de `x`, pas un nom.\n"
            },
            {
              "text": "Une erreur, `n` étant inconnu en dehors de la fonction",
              "correct": false,
              "feedback": "Erreur : le programme n'utilise `n` qu'à l'intérieur de la\nfonction, aucune erreur n'a lieu.\n"
            }
          ],
          "explanation": "Un entier passé en argument est copié dans le paramètre. Pour\nconserver le résultat, on récupère la valeur renvoyée."
        }
      ]
    }
  ]
}