# Comment définir et utiliser des variables grâce à un script Python dans vos exercices

:::success
*L'équipe FUN remercie vivement Pierre Rolin de partager son expertise avec l'ensemble du réseau FUN.*

:::

Le but de cette petite notice explicative est de monter des exemples très simples mais pratiques d'**utilisation de variables décrites dans un script python dans vos exercices**. Nous en profiterons pour exposer le moyen d'**utiliser des valeurs aléatoires et donc de faire en sorte que chaque étudiant ait un sujet dont les valeurs textuelles ou numériques soient différentes**.  
L'ensemble des exemples est décrit dans les exercices donnés en annexe. Vous pouvez simplement copier-coller ces exemples dans un exercice EdX pour voir le résultat.

Ces exemples sont issus d'un TD (Travail Dirigé) du cours « *Principe des Réseaux de Données* ».


---

## 1. Numérotez vos questions

Vous avez certainement observé que numéroter les questions est important pour la clarté de la présentation (comme dans un livre) et pour se référer à une question dans un exercice.

Sans variables il faut numéroter à la main les questions et tout ajout de question modifie toute la numérotation qui suit.

Nous vous proposons ici une solution partielle basée sur une variable.

Pour définir une variable, plus généralement une partie de code Python, il faut créer un bloc « ***script*** » comme ci-dessous

```markup
<script type="loncapa/python"> ## Balise de début du bloc
ExoNUM= "S2.L1.HW 08."
</script> ## Balise de fin du bloc
```


Vous pouvez créer ce bloc au sein d'un exercice (c'est-à-dire entre les balises `<problem>` et `</problem>`) mais je vous recommande de grouper toutes vos variables et calculs au sein d'un même bloc.

Dans cet exemple j'ai créé une variable `ExoNUM` qui contient la chaîne de caractères `S2.L1.HW 08`.


:::info
**NB** : La syntaxe est celle du langage Python et vous devez encadrer votre chaîne de caractères par des guillemets « " » ou « ' ».

:::

Dans le corps de votre exercice vous allez invoquer votre variable en la faisant précéder du signe « `$` », en italique dans le texte

`*$ExoNUM*``8:`

J'ai concaténé (mis à la suite de la variable) 8.

Ce qui sera affiché à l'écran sera donc :

`S2.L1.HW 08.8:`

 ![Figure 1 : Vue de l'écran généré par $ExoNUM8:](https://support.fun-edu.fr/api/files.get?sig=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1cGxvYWRzLzE0NGZkNTM4LTgwYjAtNDI0NS05Y2U0LTEyOGExMWRkNjI4Mi83ODUzOTFlOS1jNzAzLTQzNDEtODYzYS1iYjE0Nzk0MDg0Y2IvaW1hZ2UiLCJ0eXBlIjoiYXR0YWNobWVudCIsImlhdCI6MTc5MDA3OTMwMCwiZXhwIjoxNzkwMTY1NzAwfQ.BoZcvj5ftu6iEWZEwS6ybgnAKS9a8p8QMvuS7_Ct4hU)  
Vous pouvez voir en annexe que la question 1 de cet exercice est notée 8, la question suivante est notée 9.1, celle d'après 9.2, etc.

J'ai construit ma variable `ExoNUM` selon une règle propre à l'organisation de mon cours, *S2.L2* correspondant à *Semaine 2 - Leçon 2*.

Comme il n'y a pas moyen de récupérer automatiquement le nom de la colonne de notes j'ai ajouté le nom qui apparaît dans la notation pour cet exercice *HW 08* afin que les étudiants puissent repérer facilement leur note.

Ainsi, si vous ajoutez un exercice dans votre cours, il vous suffira de changer la variable `ExoNUM` dans le script et toutes vos questions seront préfixées par la même valeur.


---


## 2. Utiliser une variable dans le texte de vos questions ou réponses

Dans l'exercice créé dans l'annexe 1, la variable créée est `Taille_msg`. Plus loin vous trouvez une deuxième variable `Debit`. Une troisième variable `Resultat` est calculée à partir des deux variables précédentes « `Resultat = Taille_msg/Debit` » dans le bloc « ***script*** ».


:::info
**NB** : Dans un script vous utilisez le langage Python donc les variables ne sont pas précédées du signe $.

:::

Comme précédemment, vous pouvez invoquer ces variables dans une question.


***Exemple 1* :**

```markup
<p> Un utilisateur soumet un message de $Taille_msg bits pour transmission sur une voie dont le débit est de $Debit bits par secondes. Quelle est la durée de transmission de ce message en secondes (au centième près) ?</p>
```

Vous pouvez aussi invoquer une variable dans vos réponses.


***Exemple 2* :**

```xml
[explanation]
<p>Le résultat se calcule en divisant la taille du message par le débit : $Taille_msg/$Debit, soit $Resultat secondes.</p>
[explanation]
```

L'*exemple 3* utilise le balisage HTML afin de passer en français le texte généré par la balise `explanation` sur l'écran étudiant.


***Exemple 3* :**

```markup
<p>Le résultat se calcule en divisant la taille du message par le débit : $Taille_msg/$Debit, soit $Resultat secondes.</p>
</div></solution>
```


 ![Figure 2 : Résultat de l'affichage de la question et de la réponse](https://support.fun-edu.fr/api/files.get?sig=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1cGxvYWRzLzE0NGZkNTM4LTgwYjAtNDI0NS05Y2U0LTEyOGExMWRkNjI4Mi9hNmQ3ZjQwZi1lYmYwLTQwMmUtYjQ3Mi1hNmI0ZWViYmFjMmMvaW1hZ2UiLCJ0eXBlIjoiYXR0YWNobWVudCIsImlhdCI6MTc5MDA3OTMwMCwiZXhwIjoxNzkwMTY1NzAwfQ.c-sWgYvJhbsY7kC4CUGjMxHDJ7oZp4YrGUK_Fr5WQjM)  
Sur la *figure 2* la variable `*$Taille_msg*` a pris à chaque fois qu'elle apparaît (dans la question comme dans l'explication) la valeur *238024*, la variable `*$Debit*` la valeur *560 000*.  
Dans la réponse la variable `*$Resultat*` vaut *0.425042857143* (le résultat du calcul expliqué).

Jusqu'ici la valeur de la variable était constante. Si vous souhaitez que votre exercice soit personnalisé pour chaque étudiant il faut que la valeur soit tirée au hasard.


---


## 3. Affecter une valeur aléatoire à une variable

Voyons maintenant comment edX affecte une valeur à ces variables.

Dans le paramétrage de votre exercice vous avez plusieurs options qui permettent de tirer au hasard les valeurs des variables utilisées dans les questions. Dans le menu « ***paramètres*** » de chaque exercice vous pouvez choisir le type de tirage aléatoire (***randomisation***).

  
Sur la *figure 3* correspondant à l'exercice nous avons choisi la valeur « par étudiant », c'est-à-dire que le tirage sera réalisé une seule fois pour chaque étudiant. À chaque fois qu'il reviendra sur l'exercice il retrouvera la même valeur.


 ![Figure 3 : Choix du type de tirage aléatoire](https://support.fun-edu.fr/api/files.get?sig=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1cGxvYWRzLzE0NGZkNTM4LTgwYjAtNDI0NS05Y2U0LTEyOGExMWRkNjI4Mi9hMGRiOTUyNi0yOWQ3LTRjYmUtYjEwMy1hNDYzODBhODI1N2QvaW1hZ2UiLCJ0eXBlIjoiYXR0YWNobWVudCIsImlhdCI6MTc5MDA3OTMwMCwiZXhwIjoxNzkwMTY1NzAwfQ.V0_1GNuSdSfgOlYXGvDUcgrJrEAz2l_-Xj9DxvQQFws)  
Les autres modes de tirage sont :

* ***Jamais***, pas de tirage.
* ***Toujours***, un nouveau tirage est réalisé à chaque fois que l'étudiant revient sur l'exercice, si sa réponse est fausse il doit refaire l'exercice.
* ***À la remise à zéro***, un bouton apparaît alors en bas de l'exercice permettant à l'apprenant de faire l'exercice avec de nouvelles valeurs.

Revenons maintenant à la définition de nos variables. Il s'agit de code Python, nous vous présentons donc ici un tout petit aperçu des possibilités offertes.

`**Taille_msg**`` = random.randrange(80,1000000, 8)`  
La variable `**Taille_msg**` prendra une valeur aléatoire tirée au hasard dans l'intervalle [80,1000000] par pas de 8 (valeurs possibles 80, 88, 96, 104...).

Plus loin dans le code en annexe `**LongueurCable**``=random.randrange(10,10000, 1)` la variable `**LongueurCable**` rendra une valeur aléatoire tirée au hasard dans l'intervalle [10,10000] par pas de 1 (toutes les valeurs sont possibles entre 10 et 10000).

Vous pouvez vérifier sur la *figure 2* que les valeurs tirées sont bien dans les intervalles de tirage.


:::tip
En Python [10,10000], définit un tableau de 9990 valeurs possibles.

:::


Voyons maintenant le cas des 2 lignes :

`Debit_list = [1200, 2400, 4800, 9600, 19200, 560000, 64000, 128000, 256000, 512000, 1024000]`  
`**Debit**`` = Debit_list[random.randrange(0,len (Debit_list),1)]`

La variable `Debit_list` contient une liste de valeurs. Je ne l'ai pas mise en gras car je ne l'invoque pas dans le texte de l'exercice, mais rien ne l’interdit.  


:::tip
En Python :

* [10,10000] définit un tableau de 9990 valeurs numérique.


* [1200, 2400, 4800, 9600, 19200, 560000, 64000, 128000, 256000, 512000, 1024000] définit un tableau de 11 valeurs numériques que l'on obtient par la fonction Pyton len (Debit_list).


* ['bleu', 'vert', 'rouge', 'jaune'] définit un tableau de 4 valeurs textuelles.

:::


Ce que nous souhaitons dans cet exercice c'est que la variable `**Debit**` prenne une valeur au sein de cette liste seulement. Pour cela nous utilisons plusieurs fonctions Python :

`**Debit**`` = Debit_list[random.randrange(0,len (Debit_list),1)]`

  
La liste des valeurs possibles est définie dans la variable `Debit_list`,  
`randrange(0,len (Debit_list),1)` va tirer au hasard une des valeurs de ce tableau,  
`len (Debit_list)` calcule le nombre d'éléments du tableau.


:::info
**NB** : En python les numéros des éléments d'un tableau sont numérotés à partir de 0.

:::

Vous pouvez vérifier sur la *figure 2* que les valeurs tirées sont bien dans la liste des valeurs de tirage.


---


## 4. Comment corriger une question dont la valeur est tirée au hasard

Dans l'annexe les variables suivantes servent à calculer les résultats attendus aux questions.

`**DureeProgation**``=1000*(LongueurCable/220000)`  
`**DureeEmission**``=1000*(Taille_Bloc/Debit)`  
`**NbBlocs**``=DureeProgation/DureeEmission`  
`**Memoire**``= (DureeProgation * Debit )/1000`


Voyons maintenant comment poser la question de manière à ce que la bonne réponse soit vérifiée.

Toutes les réponses attendues sont des nombres donc la réponse à la question  
« Quelle est la durée de transmission de ce message en secondes (au centième près) ? » aurait dû etre demandée par :  
`= ``*$Resultat*`` +- 0.1`


Mais cela ne fonctionne pas puisqu'il faut écrire en HTML. Voici donc ce qu'il faut saisir pour obtenir la formule précédente :

`<numericalresponse answer="``*$Resultat*``">`  
`<responseparam type="tolerance" default=".01" />`  
`<formulaequationinput />`  
`</numericalresponse>`


Il vous suffit de mettre à côté de ***answer*** entre guillemets votre variable précédée de $.


Dans les questions 9.1 et 9.2 de l'annexe vous trouverez deux autres exemples.

> 
:::tip
> *Remarque :* Dans un exercice en mode « non avancé » vous pouvez mélanger du HTML et les formes usuelles. Pour obtenir la forme HTML d'une expression il suffit de faire un petit exercice avec cette expression, puis passer en mode avancé. Nous pouvons par exemple copier le résultat dans le fichier de l'éditeur extérieur à la plateforme avec lequel nous écrivons l'exercice. Vous effacez de studio l'exercice passé en mode avancé et revenez à la forme usuelle. Il vous suffit de copier le texte de votre éditeur dans l'éditeur de studio.
>
> :::


---


## 5. Comment corriger avec un programme Python

L'exercice donné en *annexe 2* demande une adresse Internet (par ex 137.194.164.14) qui débute par un nombre et contient quatres « . ».


Si nous rédigeons la réponse ainsi :   
`$ExoNUM12.1 : Quelle est la station destinataire de ce paquet ICMP (adresse IP noté a.b.c.d) ?`  
`= 137.194.164.14`  
Cela ne fonctionnera pas car edX va croire que le résultat attendu est un nombre puisqu'il débute par un chiffre.


Il faudra donc corriger la réponse dans une fonction décrite en Python dans un bloc ***script***

`def ``**test_valid_addSdV1**``(expect,ans):`  
`if (ans=="137.194.164.14"):`  
`return True`  
`else :`  
`return False`  
`</script>`

La fonction s’appelle du nom que vous voulez (par ex. **test_valid_addSdV1**), elle prend 2 paramètres « *expect* » et « *ans* ». « *ans* » prend la valeur de la réponse tapée par l'apprenant.

  
La suite est simple, nous testons si la réponse « *ans* » est égale à la réponse attendue (dans notre exemple la chaîne de caractères "137.194.164.14") .  
La fonction rend un résultat juste (True ) ou faux (False).

Pour poser la question il faut passer par la forme HTML  
`<customresponse cfn="``*test_valid_addSdV1*``">`  
`<textline math="1" />`  
`</customresponse>`

`<customresponse cfn="``*test_valid_addSdV1*``">`  
signifie que la réponse sera évaluée par la fonction test_valid_addSdV1

`<textline math="1" />`  
signifie que la boite de réponse sera de forme mathématique et que la réponse attendue de la fonction `*test_valid_addSdV1*` est 1 (valeur de True).

Vous devrez écrire une fonction spécifique avec un nom spécifique pour chaque question que vous corrigerez ainsi.

**Ceci n'est qu'une description très partielle de ce que vous pouvez faire comme correction grâce aux fonctions écrites en Python dans un script.**


---

## Annexes

### Annexe 1 : Exercice exemple

```markup
<script type="loncapa/python">
ExoNUM= "S2.L1.HW 08."

Taille_msg = random.randrange(80,1000000, 8)
Debit_list = [1200, 2400, 4800, 9600, 19200, 560000, 64000, 128000, 256000, 512000, 1024000]
Debit = Debit_list[random.randrange(0,len (Debit_list),1)]
Resultat = Taille_msg/Debit

Tailles_Blocs = [128, 256, 512, 1000, 1518, 8000, 16000]
Taille_Bloc=Tailles_Blocs[random.randrange(0,len (Tailles_Blocs),1)]
LongueurCable=random.randrange(10,10000, 1)
DureeProgation=1000*(LongueurCable/220000)
DureeEmission=1000*(Taille_Bloc/Debit)
NbBlocs=DureeProgation/DureeEmission
Memoire= (DureeProgation * Debit )/1000

</script>

$ExoNUM8:
<p>Un utilisateur soumet un message de $Taille_msg bits pour transmission sur une voie dont le débit est de $Debit bits par secondes. Quelle est la durée de transmission de ce message en secondes (au centième près) ? </p>
<numericalresponse answer="$Resultat">
<responseparam type="tolerance" default=".01" />
<formulaequationinput />
</numericalresponse>

<solution><div class="detailed-solution"><p>Explication</p>

<p>Le résultat se calcule en divisant la taille du message par le débit : $Taille_msg/$Debit, soit $Resultat secondes.</p>

</div></solution>

<p>_______________</p> $ExoNUM9:
<p> Soit un câble de $LongueurCable km. La vitesse de propagation du signal électrique sur ce câble est de 220 000 km/s. Un modem à chaque extrémité émet au débit de $Debit bit/s. </p>

$ExoNUM9.1 :
<p>Quelle est la durée de propagation en millisecondes sur ce câble ?</p>
<numericalresponse answer="$DureeProgation">
<responseparam type="tolerance" default="5%" />
<formulaequationinput />
</numericalresponse>

 

$ExoNUM9.2 :
<p>Quelle est la durée d'émission en millisecondes d'un bloc de $Taille_Bloc bits ?</p>
<numericalresponse answer="$DureeEmission">
<responseparam type="tolerance" default="5%" />
<formulaequationinput />
</numericalresponse>

$ExoNUM9.2 :
<p>En supposant que le modem émet continuellement des blocs de $Taille_Bloc bits, combien de blocs sont à tout instant en transit sur ce câble ?</p>
<numericalresponse answer="$NbBlocs">
<responseparam type="tolerance" default="5%" />
<formulaequationinput />
</numericalresponse>

 

<solution><div class="detailed-solution"><p>Explication</p>
Le délai de propagation sur ce câble de $LongueurCable km est 1000*($LongueurCable/220000) = $DureeProgation ms.
La durée d'émission d'un bloc de $Taille_Bloc bits est 1000*($Taille_Bloc / $Debit) = $DureeEmission ms.
$NbBlocs blocs de $Taille_Bloc bits sont en transit puisque le délai de propagation est de $DureeProgation ms et la durée d’émission d'un bloc est de $DureeEmission ms. Vous observez que ce câble peut être considéré comme une mémoire contenant $DureeProgation * $Debit = $Memoire bits.
La formule pour obtenir cette taille de mémoire en bits est "Durée de Propagation" * Débit.
</div></solution>
```


### Annexe 2 : Exercice exemple

```markup
<script type="loncapa/python">
ExoNUM= "S6.L7.TD 04.1. "

def test_valid_addSdV1(expect,ans):
if (ans=="137.194.164.14"):
return True
else :
return False
</script>

$ExoNUM12.1 : Quelle est la station destinataire de ce paquet ICMP (adresse IP noté a.b.c.d) ?
<customresponse cfn="test_valid_addSdV1">
<textline math="1" />
</customresponse>
```