Les nouvelles technologies pour l’enseignement des mathématiques
Intégration des TICE dans l’enseignement des mathématiques

MathémaTICE, première revue en ligne destinée à promouvoir les TICE à travers l’enseignement des mathématiques.

De Python à LaTeX : créer des fiches d’exercices aléatoires et imprimables
Article mis en ligne le 10 mars 2025
dernière modification le 8 mars 2025

par Jean-Yves Labouche

  L’intérêt des fiches d’exercices

L’apprentissage des mathématiques repose pour partie sur la répétition et l’acquisition d’automatismes. Pour aider les élèves à progresser, les enseignants ont besoin de proposer des exercices variés, en quantité suffisante, et adaptés aux compétences à travailler. Or, la création de fiches d’exercices répétitives peut rapidement devenir chronophage, surtout lorsqu’il s’agit de renouveler régulièrement les énoncés pour éviter le simple apprentissage par cœur des corrections.

Les exerciseurs interactifs, qui génèrent aléatoirement des exercices et permettent une correction immédiate, sont une solution pertinente. Cependant, ils nécessitent l’accès à un ordinateur ou une tablette, ce qui n’est pas toujours possible en classe. L’organisation d’une séance sur ces outils impose d’avoir une salle informatique disponible ce qui n’est pas toujours possible. De plus, je constate de plus en plus souvent chez mes élèves, une tendance à vouloir faire – et à faire – autre chose lorsqu’ils sont devant leur écran. Ces comportements me poussent à moins utiliser les exerciseurs, dont je suis pourtant convaincu de l’utilité, dans la classe.

C’est pourquoi je vais me pencher dans cet article sur la génération de fiches d’exercices aléatoires à imprimer. J’ai déjà montré, dans cet article, qu’il était possible d’utiliser l’IA efficacement pour le faire. Et, bien sûr, des plateformes en ligne comme l’excellent MathsALEA permettent déjà de générer des fiches d’exercices aléatoires de manière rapide et efficace.

  Alors pourquoi se lancer dans un tel travail ?

C’est l’envie de maîtriser le processus et surtout de le comprendre qui m’a poussé à aller chercher une autre solution. C’est par curiosité que j’ai exploré les pistes qui menaient à l’utilisation de scripts en langage Python pour générer des codes LaTeX. C’est le besoin de progresser dans l’usage de ces deux langages que je me suis formé. Le besoin pédagogique ou didactique n’est pas au rendez-vous dans cette phase d’apprentissage : les autres outils déjà cités y répondent parfaitement bien. Mais une fois l’outil maitrisé, ses applications viendront d’elles-mêmes.

N’étant donc expert dans aucun de ces deux langages, mon exploration, que je vais présenter ici, est sans doute incomplète et largement perfectible. Mais, je l’espère, elle donnera aux lecteurs l’envie d’aller plus loin dans cette pratique et, au minimum, l’article montrera les possibilités qu’ouvrent l’alliance de Python et LaTeX.

Une méthode pour faire ce travail est présentée par Stéphane Pasquet sur cette page de son site. Elle consiste à insérer du code Python dans une feuille de travail LaTeX grâce à l’environnement pythontex. Je m’engage dans la méthode inverse : générer la feuille LaTeX avec un programme en Python. Il ne s’agit pas d’opposer les deux méthodes : la partie de ce travail d’exploration qui m’intéressait le plus était la programmation en Python. C’est pourquoi c’est cette méthode que j’ai choisie. Elle n’est peut-être pas la meilleure.

Ce travail nécessite quelques connaissances que je n’avais pas dans ces deux langages, même s’ils m’étaient familiers. Alors il me fallait une formation ou professeur particulier pour me conseiller et me guider. Ce professeur particulier, ou assistant, a été ChatGPT : l’IA m’a indiqué des méthodes, des fonctions ou des commandes. Elle a corrigé des programmes qui ne fonctionnaient pas ou encore optimisé certaines séquences, que ce soit en Python ou en LaTeX.

Par exemple, pour la concaténation de chaînes de caractères, dont il va être grandement question dans la suite de l’article, c’est ChatGPT qui m’a fortement conseillé d’utiliser les f-strings que je ne connaissais pas. Et leur usage s’est effectivement révélé simple et efficace. Voici un exemple de demande que j’ai pu faire à ce sujet (j’ai reconstitué cette « conversation » car sa version originale était un peu chaotique du fait de mes tâtonnements). Il est vraiment très intéressant de partir d’une question assez générale puis de préciser ses demandes au fur et à mesure des réponses obtenues.

  Les outils nécessaires

Dans l’idéal, je préfère travailler avec les outils en ligne qui me semblent plus simples à utiliser, que ce soit pour programmer en Python ou pour compiler du LaTeX. Basthon (pour la programmation en Python) et Overleaf (pour l’interprétation du code LaTeX) ont donc ma préférence, j’ai l’habitude de les utiliser régulièrement.

Et si Overleaf se montrera parfaitement performant pour les tâches que je vais décrire ici, Basthon, lui, montrera certaines limites. Il est impossible d’y générer un fichier .tex avec un programme Python. Cela implique de devoir copier – coller, depuis la console de Basthon vers Overleaf, les codes LaTeX générés par les programmes. Cette manipulation n’est pas compliquée mais elle nécessite parfois de reprendre la mise en forme obtenue en LaTeX (des passages à la ligne sont ajoutés de façon intempestive). Cela est particulièrement gênant lorsque le fichier est consistant ; j’y reviendrai.

Mais comme cela est quand même plus simple et plus rapide à mettre en œuvre, je vais commencer par présenter cette solution : Basthon + Overleaf pour générer une première feuille d’exercices aléatoires. Je montrerai ensuite comment générer directement un fichier .tex en Python : il faudra alors utiliser une autre IDE.

  L’art de la concaténation des chaînes de caractères en Python

Je commence par enlever un doute : Python ne sait pas générer des formules LaTeX. Il va pourtant falloir lui faire écrire un code LaTeX assez complexe : le code LaTeX final que je vais présenter de cette partie comporte 125 lignes ! Et ces 125 lignes seront obtenues par des concaténations successives de bouts de codes que nous allons devoir saisir sous forme de chaîne de caractères. On ne peut donc pas se lancer dans cette entreprise sans une bonne connaissance du langage LaTeX permettant d’obtenir le fichier souhaité. Python ne nous sera d’aucune aide si on ne sait pas soi-même coder cette page en LaTeX.

Dès lors, on comprend assez vite que ce que je vais présenter n’est intéressant que pour des fiches d’exercices répétant plusieurs fois les mêmes séries d’exercices : si je veux créer une fiche avec des exercices tous différents alors il faut la coder directement en LaTeX.

Je vais décrire le processus qui permet d’obtenir un code complet étape par étape pour que les lecteurs non expérimentés puissent s’y retrouver. J’expliquerai chacune de ces étapes. Et n’étant moi-même pas expert dans ces deux langages, j’invite les lecteurs plus expérimentés à commenter l’article si des propositions alternatives ou des simplifications leur semblent pertinentes.

  Génération du premier exercice

Pour éviter d’alourdir inutilement le code, pour ces explications, nous allons nous contenter de quelque chose d’assez basique au niveau de la programmation en Python : un exercice de calcul mental sur les tables de multiplication. Il s’agit de générer 2 nombres aléatoires (entre 2 et 12, par exemple) et de présenter le calcul. La simplicité de cet exemple nous permettra de nous concentrer sur les commandes permettant d’obtenir la syntaxe en LaTeX.

Et nous allons commencer par ne générer qu’un seul exercice. Une simple boucle bornée permettra d’en obtenir autant que souhaité par la suite.

Voici donc le premier programme en Python que je vais expliquer :

from random import randint
# Génération des deux nombres
a = randint(2, 12)
b = randint(2, 12)
# Génération du code LaTeX
code_latex = f"\\documentclass{{article}}\n\\begin{{document}}\nCalculer : \\\ $ {a} \\times {b} = $ ?\n\\end{{document}}"
# Affichage du code LaTeX
print(code_latex)
Voir et tester dans Basthon Télécharger le fichier

Comme son nom l’indique, la variable code_latex contient le texte formaté en LaTeX qui est généré par le programme. Ce texte est construit progressivement en concaténant différentes parties du code LaTeX. La variable est affichée en fin de programme : il ne reste plus qu’à la copier-coller dans l’interpréteur LaTeX.

La définition de cette variable nécessite quelques explications :

  • Le point essentiel : la lettre f devant la chaine de caractère indique qu’il s’agit d’un f-string : il est alors possible d’insérer les valeurs de variables dans cette chaîne en plaçant ces variables entre accolades (ici les variables a et b). Plus d’explications sur les f-strings sur cette page ou dans ma conversation avec ChatGPT déjà partagée plus haut. Ce type de chaîne de caractères simplifie grandement la concaténation souhaitée.
  • Il s’agit d’une chaîne de caractère, raison pour laquelle elle est entre guillemets.
  • \documentclass{article} : commande LaTeX. Elle donne le type du document, qui sera un article LaTeX.
  • \begin{document} : commande LaTeX. Elle indique le début du document.
  • \\ : commande LaTeX. Elle permet un retour à la ligne dans le document LaTeX.
  • \times : commande LaTeX : signe de la multiplication.
  • \end{document} : commande LaTeX. Elle indique la fin du document.

Le problème dans l’utilisation de ces commandes LaTeX qui commencent toutes par un \ est que Python, normalement, interprète les commandes qui commence précisément par un \ (ces commandes sont les échappements). Pour éviter cela, on place un premier \ devant ces commandes LaTeX pour éviter que Python les interprète comme n’étant pas du texte (là encore voire ma conversation avec ChatGPT qui me l’explique très bien).

Autre problème : les chaînes de caractères formatées (f-strings) permettent l’insertion simple de variables en plaçant ces dernières entre accolades. Mais si on souhaite que des accolades apparaissent dans notre chaîne de caractères (sans utiliser de variable) alors il faut les placer elles-mêmes entre accolades. Ce qui explique les doubles accolades {{…}} pour ces commandes en LaTeX.

Il faut donc utiliser les syntaxes suivantes pour ces commandes :

  • \\documentclass{{article}}
  • \\begin{{document}}
  • \\\
  • \\times
  • \\end{{document}}

\n : Ajoute des sauts de ligne dans le code Python (pour une meilleure lisibilité du code LaTeX qui, sans cette commande, serait généré sur une seule ligne). Le format f-string le convertit automatiquement, il est donc inutile d’avoir un quelconque séparateur.

Si on exécute ce programme dans Basthon, on obtient dans la console le code LaTeX, qu’il faut donc copier – coller dans un interpréteur. Voici ce code LaTeX obtenu :

\documentclass{article}
\begin{document}
Calculer : 
$ 7 \times 11 = $ ?
\end{document}

Après compilation, on obtient le résultat suivant :

Voir le résultat obtenu dans Overleaf.

Cette première étape est la plus compliquée à franchir. En effet, ensuite il s’agit d’ajouter des lignes de code assez accessibles à qui est habitué à manipuler Python et LaTeX.

  Génération d’une série d’exercices

Nous pouvons donc maintenant nous lancer dans la création d’une série d’exercices. L’ajout d’une boucle bornée fera l’affaire.
Une partie du code LaTeX doit être généré avant cette boucle : il sera simple de concaténer les différentes parties en fin de programme pour pouvoir afficher le code complet.

Voici le programme permettant de générer 10 exercices :

from random import randint

# Nombre d'exercices à générer
n = 10

# Génération des exercices en LaTeX
code_1 = "\\documentclass{article}\n\\begin{document}\n\\textbf{Calcul mental}\\\\\\\\\n"

code_2= ""
for i in range(n):
    a = randint(2, 12)
    b = randint(2, 12)
    code_2 += f"{i+1}. $ {a} \\times {b} = $ ?\\\\\n"

code_3 = "\\end{document}"

# Concaténation des 3 "bouts" de code
code_latex = code_1 + code_2 + code_3 

# Affichage du code LaTeX
print(code_latex)

Voir et tester dans Basthon) Télécharger le fichier

Remarque  : ici les chaînes de caractères code_1 et code_3 ne sont pas de f-stings (elles ne contiennent pas de variables). De simples accolades sont donc utilisées pour les commandes LaTeX. Par contre les double backslashs \\ y sont toujours nécessaires.

Le code LaTex généré est le suivant, avec le rendu une fois interprété :

\documentclass{article}
\begin{document}
\textbf{Calcul mental}\\\\
1. $ 11 \times 12 = $ ?\\
2. $ 3 \times 5 = $ ?\\
3. $ 12 \times 12 = $ ?\\
4. $ 6 \times 8 = $ ?\\
5. $ 11 \times 9 = $ ?\\
6. $ 3 \times 6 = $ ?\\
7. $ 8 \times 2 = $ ?\\
8. $ 2 \times 9 = $ ?\\
9. $ 7 \times 7 = $ ?\\
10. $ 7 \times 2 = $ ?\\
\end{document}


Voir le résultat obtenu dans Overleaf.

  Quelques améliorations

Les spécialistes de LaTeX pourront se faire plaisir en adoptant une mise en page bien plus élaborée de la feuille de travail.

Je propose ces améliorations simples :

  • Numérotation des questions avec la structure suivante :
    \begin{enumerate}
    \item …
    \item …
    …
    \end{enumerate} 
    
  • Le saut de ligne géré par \medskip.
  • Présentation sur 2 colonnes avec l’environnement multicol.
  • Encadré avec l’environnement tcolorbox.
  • Le point d’interrogation après le calcul à effectuer est remplacé par une ligne horizontale sur laquelle l’élève pourra écrire. C’est la commande LaTeX \underline{\hspace{1cm}}.

Voici le code Python que j’obtiens :

from random import randint

# Nombre d'exercices à générer
n = 10

# Partie 1 : Début du document LaTeX avec un titre et l'encodage UTF-8
code_1 = (
    "\\documentclass{article}\n"
    "\\usepackage{multicol}\n"
    "\\usepackage{tcolorbox}\n"
    "\\begin{document}\n"
    "\\section*{Calcul mental - Tables de multiplications}\n"
    "Calculer les produits suivants :\n\n"
    "\\begin{tcolorbox}[title=Série 1, colframe=blue!50!black, colback=blue!3!white]\n"
    "\\begin{multicols}{2}\n"
    "\\begin{enumerate}\n"
)

# Partie 2 : Génération des exercices de multiplication
code_2 = ""
for i in range(n):
    a = randint(2, 12)
    b = randint(2, 12)
    code_2 += f"    \\item $ {a} \\times {b} = $ \\underline{{\hspace{{1cm}}}} \\medskip\n"

# Partie 3 : Fin du document LaTeX
code_3 = "\\end{enumerate}\n\\end{multicols}\n\\end{tcolorbox}\n\\end{document}"

# Concaténation des trois parties
code_latex = code_1 + code_2 + code_3 

# Affichage du code LaTeX
print(code_latex)

Voir et tester dans Basthon Télécharger le fichier

Ici, la variable code_1 est une chaîne de caractère un peu longue et elle est assez illisible si elle est placée en une seule ligne. Pour plus de clarté, j’utilise une concaténation de plusieurs chaînes de caractères courtes, chacune correspondant à une ligne du code LaTeX. Pour cela, j’utilise le fait que, dans Python, les chaînes de caractères peuvent être concaténées automatiquement lorsqu’elles sont écrites entre parenthèses. Le résultat est plus lisible et il sera ainsi plus simple de le modifier ou de le corriger si besoin.

Le code LaTeX ainsi généré est le suivant, avec le rendu :

\documentclass{article}
\usepackage{multicol}
\usepackage{tcolorbox}
\begin{document}
\section*{Calcul mental - Tables de multiplications}
Calculer les produits suivants :

\begin{tcolorbox}[title=Série 1, colframe=blue!50!black, colback=blue!3!white]
\begin{multicols}{2}
\begin{enumerate}
    \item $ 8 \times 4 = $ \underline{\hspace{1cm}} \medskip
    \item $ 11 \times 10 = $ \underline{\hspace{1cm}} \medskip
    \item $ 5 \times 3 = $ \underline{\hspace{1cm}} \medskip
    \item $ 8 \times 8 = $ \underline{\hspace{1cm}} \medskip
    \item $ 9 \times 12 = $ \underline{\hspace{1cm}} \medskip
    \item $ 9 \times 7 = $ \underline{\hspace{1cm}} \medskip
    \item $ 6 \times 11 = $ \underline{\hspace{1cm}} \medskip
    \item $ 8 \times 12 = $ \underline{\hspace{1cm}} \medskip
    \item $ 8 \times 2 = $ \underline{\hspace{1cm}} \medskip
    \item $ 12 \times 7 = $ \underline{\hspace{1cm}} \medskip
\end{enumerate}
\end{multicols}
\end{tcolorbox}
\end{document}

Voir le résultat obtenu dans Overleaf.

Attention !
Lorsque l’on effectue le copier-coller depuis la console de Basthon, des retours à la ligne sont ajoutés là où il y a un retour à la ligne sur votre écran. Par exemple, si je copie cette console :

Lorsque je la colle dans Overleaf, j’obtient ceci :

La ligne 5 est coupée par un retour à la ligne non souhaité. Cela peut avoir des conséquences gênantes sur le code LaTeX obtenu et cela oblige à le reprendre manuellement pour supprimer ces passages à la ligne. Sur un code un peu long, c’est compliqué. Un moyen d’y remédier est de dézoomer la page de Basthon (dans le navigateur) pour que les lignes ne soient plus coupées. Comme ci-dessous :

  Dernière étape : ajouter des séries d’exercices et les corrections

Ici nous créons 3 séries identiques à la précédente en utilisant des boucles imbriquées. Les corrections des exercices seront placées sur une deuxième page. La génération des exercices et celle des corrections doivent se faire en « simultané » : dans la mesure où nous n’utilisons que 2 variables pour les calculs (a et b), leurs valeurs sont perdues dès que le programme génère le calcul suivant. Les concaténations des deux chaînes code_exercices et code_corrections se font donc dans les même parties du programme, l’une après l’autre, et avant que les variables ne soient recalculées.

from random import randint

# Nombre d'exercices par série
n = 12
nombre_de_serie = 3  # Nombre de séries

# Début du document LaTeX
code_1 = (
    "\\documentclass{article}\n"
    "\\usepackage[utf8]{inputenc}\n"
    "\\usepackage{xcolor}\n"
    "\\usepackage{multicol}\n"
    "\\usepackage{tcolorbox}\n"
    "\\begin{document}\n"
    "\\section*{Calcul mental - Tables de multiplications}\n"
    "Pour chaque série, calculer les produits demandés :\n\n")

# Génération des exercices et stockage des corrections
code_exercices = ""
code_corrections = "\\newpage\n\\section*{Corrections}\n"

for k in range(nombre_de_serie):
    # Encadré de la série
    code_exercices += f"\\begin{{tcolorbox}}[title=Série {k+1}, colframe=blue!50!black, colback=blue!3!white]\n"
    code_exercices += "\\begin{multicols}{3}\n\\begin{enumerate}\n"

    code_corrections += f"\\begin{{tcolorbox}}[title=Correction Série {k+1}, colframe=red!50!black, colback=red!3!white]\n"
    code_corrections += "\\begin{multicols}{3}\n\\begin{enumerate}\n"

    for i in range(n):
        a = randint(2, 12)
        b = randint(2, 12)
        produit = a * b
        
        # Génération des exercices
        code_exercices += f"    \\item $ {a} \\times {b} = $ \\underline{{\\hspace{{1cm}}}} \\medskip\n"

        # Génération des corrections
        code_corrections += f"    \\item $ {a} \\times {b} = $ \\textbf{{\\textcolor{{red}}{{{produit}}}}} \\medskip\n"

    # Fermeture des environnements pour la série
    code_exercices += "\\end{enumerate}\n\\end{multicols}\n\\end{tcolorbox}\n\n"
    code_corrections += "\\end{enumerate}\n\\end{multicols}\n\\end{tcolorbox}\n\n"

# Fin du document LaTeX
code_fin = "\\end{document}"

# Concaténation des parties
code_latex = code_1 + code_exercices + code_corrections + code_fin

# Affichage du code LaTeX
print(code_latex)
Voir et tester dans Basthon Télécharger le fichier
Voir le résultat obtenu dans Overleaf

Et voilà comment ce programme Python d’une trentaine de lignes (si on ne compte ni les lignes vides ni les lignes de commentaires) permet de générer un code LaTeX de 125 lignes !

  Quelques variations

En gardant la même structure de programme, il est possible de varier les plaisirs. Voici deux exemples :

  • Somme de fractions
Voir et tester dans Basthon Télécharger le fichier
Voir le résultat dans Overleaf
  • Développer une expression littérale avec la double distributivité
Voir et tester dans Basthon Télécharger le fichier
Voir le résultat dans Overleaf

Le plus compliqué et chronophage dans la préparation de ces fichiers pas la mise en forme du code LaTeX : on conserve la structure du fichier précédent, il n’y a pas grand-chose à ajouter. C’est plutôt la génération des questions et surtout de leurs corrections, si on veut la détailler, qui prendront du temps.

  Générer directement un fichier LaTeX

La manipulation qui consiste à copier-coller le code LaTeX depuis la console de Baston vers un éditeur LaTeX n’est pas franchement satisfaisante.
Basthon ne permet pas de générer un fichier à partir d’un code en Python, mais d’autres IDE le font. Repl.it si on veut rester en ligne sinon, en local, cela fonctionne bien.

Pour générer un tel fichier, il faut juste supprimer la dernière ligne de notre programme et la remplacer par celles-ci dessous :

# Écriture dans un fichier .tex
with open("exercices_developpement.tex", "w", encoding="utf-8") as f:
    f.write(code_latex)

print("Le fichier exercices_developpement.tex a été généré avec succès.")

Le fichier exercices_developpement.tex est créé et sera accessible sous le nom f à l’intérieur du bloc with. La fonction write() permet d’écrire le contenu de notre variable code_latex dans ce nouveau fichier. La structure with open(...) as f: assure que le fichier est automatiquement fermé après l’exécution du bloc.

Le fichier LaTeX ainsi obtenu est strictement identique que le précédent. Il n’y a pas eu besoin de manipulation : on peut l’ouvrir dans l’éditeur LaTeX.

Télécharger le fichier Python :

  Une IA générative pour se former

Vous l’avez compris, c’est essentiellement la curiosité qui m’a poussé à me diriger vers ces expérimentations que j’ai partagées dans cet article. Il ne s’agit qu’un début, une introduction à cette « collaboration » entre deux outils puissants et indispensables que sont Python et LaTeX.

Et comme je l’ai mentionné rapidement en début d’article, les IA génératives étant assez expertes en programmation, elles se transforment facilement en un professeur particulier performant pour peu que l’on sache formuler nos demandes. Mes requêtes et demandes de relectures de codes à ChatGPT m’ont fait gagner un temps non négligeable. Je ne serais peut-être pas arrivé à mes fins sans ses conseils et explications. Cela ne m’a dispensé de faire des recherches par ailleurs, mais ce fut un assistant précieux.

Je n’aurai jamais pensé dire ça il y a très peu de temps encore : ma formation professionnelle, au moins dans certains domaines, s’est accélérée grâce à l’intelligence artificielle.