diff --git a/conditions_boucles.ipynb b/2_base_programmation.ipynb similarity index 57% rename from conditions_boucles.ipynb rename to 2_base_programmation.ipynb index 6ab61d2..203691c 100644 --- a/conditions_boucles.ipynb +++ b/2_base_programmation.ipynb @@ -29,14 +29,14 @@ "metadata": {}, "cell_type": "markdown", "source": [ - "|Opérateur| Signification |\n", - "|-|----------------------|\n", - "|==| Égale à |\n", - "|!=| Différent de |\n", - "|<| Inférieur à |\n", - "|<=| Inférieur ou égale à |\n", - "|>| Supérieur à |\n", - "|>=| Supérieur ou égale à |\n" + "| Opérateur | Signification |\n", + "|-----------|----------------------|\n", + "| == | Égale à |\n", + "| != | Différent de |\n", + "| < | Inférieur à |\n", + "| <= | Inférieur ou égale à |\n", + "| \\> | Supérieur à |\n", + "| \\>= | Supérieur ou égale à |\n" ] }, { @@ -57,7 +57,13 @@ { "metadata": {}, "cell_type": "markdown", - "source": "|Opérateur|Signification|\n|-|-|\n|and|ET Logique|\n|or|OU Logique|\n|not|NON Logique|" + "source": [ + "| Opérateur | Signification |\n", + "|-----------|---------------|\n", + "| and | ET Logique |\n", + "| or | OU Logique |\n", + "| not | NON Logique |" + ] }, { "metadata": {}, @@ -82,12 +88,21 @@ { "metadata": {}, "cell_type": "markdown", - "source": "Toutes les valeurs décimales (exprimées en base 10 càd 10 symboles) seront converties en valeurs binaires (séquence de bits donc suite de 0 et/ou 1 comme par exemple 0010 1100, ...). Ces opérateurs binaires effectuent donc des opérations bit à bit. " + "source": "Toutes les valeurs décimales (exprimées en base 10 c.-à-d. 10 symboles) seront converties en valeurs binaires (séquence de bits donc suite de 0 et/ou 1 comme par exemple 0010 1100, ...). Ces opérateurs binaires effectuent donc des opérations bit à bit. " }, { "metadata": {}, "cell_type": "markdown", - "source": "|Opérateur|Signification|\n|-|-|\n|&|ET Logique|\n|\\||OU Logique|\n|~|NON Logique|\n|^|OU Exclusif: XOR|\n|>>|Décalage binaire à droite|\n|<<|Décalage binaire à gauche|" + "source": [ + "| Opérateur | Signification |\n", + "|-----------|---------------------------|\n", + "| & | ET Logique |\n", + "| \\| | OU Logique |\n", + "| ~ | NON Logique |\n", + "| ^ | OU Exclusif: XOR |\n", + "| \\>\\> | Décalage binaire à droite |\n", + "| << | Décalage binaire à gauche |" + ] }, { "metadata": {}, @@ -102,7 +117,12 @@ { "metadata": {}, "cell_type": "markdown", - "source": "|Opérateur|Signification|\n|-|-|\n|is|Est le même objet|\n|is not|N'est pas le même objet|" + "source": [ + "| Opérateur | Signification |\n", + "|-----------|-------------------------|\n", + "| is | Est le même objet |\n", + "| is not | N'est pas le même objet |" + ] }, { "metadata": {}, @@ -117,7 +137,12 @@ { "metadata": {}, "cell_type": "markdown", - "source": "|Opérateur|Signification|\n|-|-|\n|in|Est dans l'objet|\n|not in|N'est pas dans l'objet|" + "source": [ + "| Opérateur | Signification |\n", + "|-----------|------------------------|\n", + "| in | Est dans l'objet |\n", + "| not in | N'est pas dans l'objet |" + ] }, { "metadata": {}, @@ -132,7 +157,23 @@ { "metadata": {}, "cell_type": "markdown", - "source": "|Opérateur|Signification|Exemple|Equivalent à|\n|-|-|-|-|\n|+=|Addition et affectation|a+=b|a=a+b|\n|-=|Soustraction et affectation|a-=b|a=a-b|\n|\\*=|Multiplication et affectation|a\\*=b|a=a\\*b|\n|/=|Division et affectation|a/=b|a=a/b|\n|%=|Modulo et affectation|a%=b|a=a%b|\n|//=|Division entière et affectation|a//=b|a=a//b|\n|\\*\\*=|Exponentiation et affectation|a\\*\\*=b|a=a\\*\\*b|\n|&=|ET bit à bit et affectation|a&=b|a=a&b|\n|\\|=|OU bit à bit et affectation|a\\|=b|a=a\\|b|\n|^=|XOR et affectation|a^=b|a=a^b|\n|>>=|Décalage binaire à droite et affectation|a>>=b|a=a>>b|\n|<<=|Décalage binaire à gauche et affectation|a<<=b|a=a<>= | Décalage binaire à droite et affectation | a>>=b | a=a>>b |\n", + "| <<= | Décalage binaire à gauche et affectation | a<<=b | a=a< 2\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[43mcondition1\u001B[49m:\n\u001B[1;32m 3\u001B[0m instruction1\n\u001B[1;32m 4\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m condition2:\n", + "\u001B[0;31mNameError\u001B[0m: name 'condition1' is not defined" + ] + } + ], + "execution_count": 1 }, { "metadata": {}, "cell_type": "markdown", - "source": "En fonction de la condition remplie, c'est une instruction précise qui sera exécutée. \n- Ainsi, si la *condition1* est True alors l'*instruction1* sera exécutée, les autres instructions ne seront pas exécutées !\n- Si la *condition1* est False, et que la *condition2* est True alors l'*instruction2* sera exécutée, les autres instructions ne seront pas exécutées !\n- etc...\n- Si aucune condition précédente n'est True, alors l'*instruction4* sera exécutée. " + "source": [ + "En fonction de la condition remplie, c'est une instruction précise qui sera exécutée. \n", + "- Ainsi, si la *condition1* est True alors l'*instruction1* sera exécutée, les autres instructions ne seront pas exécutées !\n", + "- Si la *condition1* est False, et que la *condition2* est True alors l'*instruction2* sera exécutée, les autres instructions ne seront pas exécutées !\n", + "- etc...\n", + "- Si aucune condition précédente n'est True, alors l'*instruction4* sera exécutée.\n", + "C'est l'équivalent du switch/case dans d'autres langages." + ] }, { "metadata": {}, @@ -183,15 +247,19 @@ "trusted": false }, "cell_type": "code", - "source": "#Exemple d'utilisation d'une boucle if\nval1 = 10\nval2 = 6\nif val1 < val2:\n print(val1, \" est plus petit que \", val2)\nelif val1 > val2:\n print(val2, \" est plus petit que \", val1)\nelse:\n print(\"Les deux variables ont la même valeur: \", val1)\n ", - "execution_count": 11, - "outputs": [ - { - "output_type": "stream", - "text": "6 est plus petit que 10\n", - "name": "stdout" - } - ] + "source": [ + "#Exemple d'utilisation d'une boucle if\n", + "val1 = 10\n", + "val2 = 6\n", + "if val1 < val2:\n", + " print(val1, \" est plus petit que \", val2)\n", + "elif val1 > val2:\n", + " print(val2, \" est plus petit que \", val1)\n", + "else:\n", + " print(\"Les deux variables ont la même valeur: \", val1)\n" + ], + "outputs": [], + "execution_count": null }, { "metadata": {}, @@ -204,14 +272,8 @@ }, "cell_type": "code", "source": "#Exemple d'une boucle if else sur une seule ligne\nval1 = 10\nval2 = 6\nprint(val1, \" est plus petit que \", val2) if val1 == val2 else print(\"les deux variables n'ont pas la même valeur\")", - "execution_count": 14, - "outputs": [ - { - "output_type": "stream", - "text": "les deux variables n'ont pas la même valeur\n", - "name": "stdout" - } - ] + "outputs": [], + "execution_count": null }, { "metadata": {}, @@ -227,7 +289,7 @@ "metadata": {}, "cell_type": "markdown", "source": [ - "Écrire un script Python qui vérifie si un nombre saisi par l'utilisateur est un nombre pair ou impair. \n", + "Écrire un script Python appelé `isodd.py` qui vérifie si un nombre saisi par l'utilisateur est un nombre pair ou impair. \n", "- Attention aux commentaires\n", "- Attention aux noms de variables. \n", "*Faites valider votre script ainsi que son exécution.* " @@ -242,7 +304,8 @@ "metadata": {}, "cell_type": "markdown", "source": [ - "Écrire un script Python qui vérifie si une année saisie par l'utilisateur est une année bissextile ou non. \n", + "Écrire un script Python appelé `leap_year.py` qui vérifie si une année saisie par l'utilisateur est une année bissextile ou non.\n", + "Sachant qu'une année est bissextile si elle est divisible par 4 ou 100 ou 400.\n", "- Attention aux commentaires\n", "- Attention aux noms de variables. \n", "*Faites valider votre script ainsi que son exécution*. " @@ -257,9 +320,9 @@ "metadata": {}, "cell_type": "markdown", "source": [ - "Sur différentes consoles de jeu, on peut jouer à des jeux qui permettent de calculer notre masse idéale en connaissant notre taille en fonction de l'IMC (Indice de Masse Corporelle). De même, il est également possible de calculer votre IMC en fonction de votre taille et votre masse réelle. L'IMC est calculée grâce à la formule:\n", + "Calculer notre masse idéale en connaissant notre taille en fonction de l'IMC (Indice de Masse Corporelle). De même, il est également possible de calculer votre IMC en fonction de votre taille et votre masse réelle. L'IMC est calculée grâce à la formule:\n", "- Masse = IMC x Taille² \n", - "*Masse est exprimée en kilogrammes et la Taille en mètres*\n", + "*Masse est exprimée en kilogramme et la Taille en mètre*\n", "\n", "Une personne de corpulence \"normale\" a un IMC entre 18.5 et 24,9. Un IMC supérieur à 24,9 signifie que la personne est en surpoids. À l'inverse, un IMC inférieur à 18,5 la personne est en maigreur. Le schéma ci-dessous présente les différentes tranches de corpulence en fonction de la valeur de l'IMC. " ] @@ -267,7 +330,14 @@ { "metadata": {}, "cell_type": "markdown", - "source": "1. Écrire un script Python qui calcule l'intervalle de poids \"idéal\" d'un utilisateur ayant saisi au préalable sa taille.\n2. Écrire un script Python de coaching qui à partir de la taille et de la masse saisies par l'utilisateur, calcule l'IMC et affiche un conseil nutritionnel ou sportif. " + "source": [ + "1. Écrire un script Python appelé `ideal_bmi.py` qui calcule l'intervalle de poids \"idéal\" d'un utilisateur ayant saisi au préalable sa taille.\n", + "2. Écrire un script Python appelé `compute_bmi.py` de coaching qui à partir de la taille et de la masse saisies par l'utilisateur, calcule l'IMC et affiche un conseil nutritionnel ou sportif. \n", + "\n", + "- Attention aux commentaires\n", + "- Attention aux noms de variables. \n", + "*Faites valider votre script ainsi que son exécution*. " + ] } ], "metadata": { diff --git a/boucles_iteratives.ipynb b/3_boucles_iteratives.ipynb similarity index 74% rename from boucles_iteratives.ipynb rename to 3_boucles_iteratives.ipynb index 2f0f051..7e93e08 100644 --- a/boucles_iteratives.ipynb +++ b/3_boucles_iteratives.ipynb @@ -13,7 +13,13 @@ { "metadata": {}, "cell_type": "markdown", - "source": "Les structures itératives permettent d'exécuter une partie du code un certain nombre de fois. Le nombre de répétitions peut être connu ou inconnu. En fonction du cas de figure, une structure en particulier sera utilisée. \nPrenons un exemple simple qui consiste à programmer les déplacements d'un robot afin de gravir des marches. \nDeux cas de figure peuvent se présenter: \n* Soit le nombre de marches ) gravir est inconnu et dans ce cas il convient préciser au robot de gravir une marche à chaque fois qu'il en détecte une. \n* Soit le nombre de marches à gravir est connu et dans ce cas il suffit de spécifier au robot: Monte X marches (X étant un nombre entier). \n " + "source": [ + "Les structures itératives permettent d'exécuter une partie du code un certain nombre de fois. Le nombre de répétitions peut être connu ou inconnu. En fonction du cas de figure, une structure en particulier sera utilisée. \n", + "Prenons un exemple simple qui consiste à programmer les déplacements d'un robot afin de gravir des marches. \n", + "Deux cas de figure peuvent se présenter: \n", + "* Soit le nombre de marches à gravir est inconnu et dans ce cas, il convient préciser au robot de gravir une marche à chaque fois qu'il en détecte une. \n", + "* Soit le nombre de marches à gravir est connu et alors, il suffit de spécifier au robot: Monte X marches (X étant un nombre entier)." + ] }, { "metadata": {}, @@ -23,35 +29,58 @@ { "metadata": {}, "cell_type": "markdown", - "source": "La première structure concerne le cas où le nombre de répétitions est inconnu. Dans ce cas il est nécessaire de spécifier une condition à respecter. \nSi nous reprenons l'exemple du robot avec un nombre de marches inconnu, la condition peut être *Tant que tu vois une marche alors tu montes*. " + "source": [ + "La première structure concerne le cas où le nombre de répétitions est inconnu. Dans ce cas, il est nécessaire de spécifier une condition à respecter. \n", + "Si nous reprenons l'exemple du robot avec un nombre de marches inconnu, la condition peut être *Tant que tu vois une marche alors tu montes*. " + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T08:45:05.015557Z", + "start_time": "2024-10-08T08:45:04.993879Z" + } }, "cell_type": "code", "source": "#Syntaxe d'écriture\nwhile condition1:\n instruction1\ninstruction2", - "execution_count": null, - "outputs": [] + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'condition1' is not defined", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mNameError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[98], line 2\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[38;5;66;03m#Syntaxe d'écriture\u001B[39;00m\n\u001B[0;32m----> 2\u001B[0m \u001B[38;5;28;01mwhile\u001B[39;00m \u001B[43mcondition1\u001B[49m:\n\u001B[1;32m 3\u001B[0m instruction1\n\u001B[1;32m 4\u001B[0m instruction2\n", + "\u001B[0;31mNameError\u001B[0m: name 'condition1' is not defined" + ] + } + ], + "execution_count": 98 }, { "metadata": {}, "cell_type": "markdown", - "source": "Lorsque *condition1* est Vraie alors *instruction1* est exécutée. SI *condition1* n'est pas Vraie donc Fausse alors *instcruction2* est exécutée. *instruction2* sera exécutée quoi qu'il arrive, c'est-à-dire que *condition1* soit vérifiée ou non, car elle se situe en dehors de la boucle *while*. " + "source": "Lorsque *condition1* est Vraie alors *instruction1* est exécutée. SI *condition1* n'est pas Vraie donc Fausse alors *instruction2* est exécutée. *instruction2* sera exécutée quoi qu'il arrive, c'est-à-dire que *condition1* soit vérifiée ou non, car elle se situe en dehors de la boucle *while*." }, { "metadata": {}, "cell_type": "markdown", - "source": "En Python, les instructions sont indentées par rapport aux tests sur les conditions. Le corps de ces instructions commence par une indentation et la première ligne non indentée marque leur fin. " + "source": "En Python, les instructions sont indentées par rapport aux tests sur les conditions. Le corps de ces instructions commence par une indentation et la première ligne non indentée marque leur fin." }, { "metadata": {}, "cell_type": "markdown", - "source": "Python interprète les valeurs non nulles comme True. *None* et *0* sont interprétés comme False. " + "source": "Python interprète les valeurs non nulles comme True. *None* et *0* sont interprétés comme False." }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T08:45:05.256785Z", + "start_time": "2024-10-08T08:45:05.250456Z" + } }, "cell_type": "code", "source": [ @@ -64,29 +93,42 @@ " cpt += 1\n", "print(\"Pair en \", cpt, \" coups\")" ], - "execution_count": 11, "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "try again !\nPair en 2 coups\n", - "name": "stdout" + "text": [ + "try again !\n", + "Pair en 2 coups\n" + ] } - ] + ], + "execution_count": 99 }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T08:45:05.314555Z", + "start_time": "2024-10-08T08:45:05.307534Z" + } }, "cell_type": "code", "source": "#Exemple 2 d'utilisation d'une boucle while\ni = 0\nwhile i < 4:\n print(\"i est égale à: \", i)\n i += 1\nprint(\"Fin de la boucle While, i = \", i)", - "execution_count": 13, "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "i est égale à: 0\ni est égale à: 1\ni est égale à: 2\ni est égale à: 3\nFin de la boucle While, i = 4\n", - "name": "stdout" + "text": [ + "i est égale à: 0\n", + "i est égale à: 1\n", + "i est égale à: 2\n", + "i est égale à: 3\n", + "Fin de la boucle While, i = 4\n" + ] } - ] + ], + "execution_count": 100 }, { "metadata": {}, @@ -96,7 +138,18 @@ { "metadata": {}, "cell_type": "markdown", - "source": "**Jeu du plus ou mois !** \nL'ordinateur tire un nombre entier au hasard entre 0 et 100. \nL'utilisateur doit le trouver et pour cela il propose des valeurs. \nL'ordinateur indique pour chaque valeur proposée si elle est trop petite, trop grande ou s'il a trouvé ! \n\nÉcrire un script Python qui permet de jouer à ce jeu. En combien de coups est-on sûr de trouver? \nModifier votre script Python pour que le programme s'arrête si l'utilisateur n'a pas trouvé le bon nombre au bout d'un nombre de coups définit au préalable. \n- Attention aux commentaires\n- Attention aux noms de variables. \n*Faites valider votre script ainsi que son exécution.* " + "source": [ + "**Jeu du plus ou mois !** \n", + "L'ordinateur tire un nombre entier au hasard entre 0 et 100. \n", + "L'utilisateur doit le trouver et pour cela il propose des valeurs.\n", + "L'ordinateur indique pour chaque valeur proposée si elle est trop petite, trop grande ou s'il a trouvé ! \n", + "\n", + "Écrire un script Python qui permet de jouer à ce jeu. En combien de coups est-on sûr de trouver? \n", + "Modifier votre script Python pour que le programme s'arrête si l'utilisateur n'a pas trouvé le bon nombre au bout d'un nombre de coups définit au préalable. \n", + "- Attention aux commentaires\n", + "- Attention aux noms de variables. \n", + "*Faites valider votre script ainsi que son exécution.* " + ] }, { "metadata": {}, @@ -116,7 +169,19 @@ { "metadata": {}, "cell_type": "markdown", - "source": "**Mercato** \nC'est la période des transferts et un joueur, un attaquant, est convoité par le FC Saint-Michel et l'AS Gabriel Fauré, qui lui proposent le même salaire mensuel mais des systèmes différents pour les primes de buts marqués. \n* Le FC Saint-Michel lui propose une prime de 8000€ par but marqué pour les 10 premiers buts marqués puis 11300€ par but marqué à partir du 11e but. \n* L'AS Gabriel Fauré lui propose une prime de 10000€ par but marqué quel que soit le nombre de buts marqués. \n1. Si l'attaquant inscrit 12 buts lors de la saison, dans quel club touchera-t-il la prime la plus importante? Justifier votre réponse. \n2. Écrire un script Python qui demande à l'utilisateur de saisir le nombre de buts inscrits et qui calcule les montants des primes offertes par les deux clubs cités ci-dessus. \n3. Écrire un script Python qui détermine le nombre de buts que doit marquer l'attaquant pour que le montant de la prime offerte par l'autre club que celui désigné à la question 1, soit plus intéressante.\n- Pensez à utiliser une boucle for\n- Attention aux commentaires\n- Attention aux noms de variables. \n*Faites valider votre script ainsi que son exécution*. \n" + "source": [ + "**Mercato** \n", + "C'est la période des transferts et un joueur, un attaquant, est convoité par le FC Saint-Michel et l'AS Gabriel Fauré, qui lui proposent le même salaire mensuel mais des systèmes différents pour les primes de buts marqués. \n", + "* Le FC Saint-Michel lui propose une prime de 8000 € par but marqué pour les 10 premiers buts marqués puis 11300 € par but marqué à partir du 11e but. \n", + "* L'AS Gabriel Fauré lui propose une prime de 10000 € par but marqué quel que soit le nombre de buts marqués. \n", + "1. Si l'attaquant inscrit 12 buts lors de la saison, dans quel club touchera-t-il la prime la plus importante ? Justifier votre réponse. \n", + "2. Écrire un script Python qui demande à l'utilisateur de saisir le nombre de buts inscrits et qui calcule les montants des primes offertes par les deux clubs cités ci-dessus. \n", + "3. Écrire un script Python qui détermine le nombre de buts que doit marquer l'attaquant pour que le montant de la prime offerte par l'autre club que celui désigné à la question 1, soit plus intéressante.\n", + "- Pensez à utiliser une boucle for\n", + "- Attention aux commentaires\n", + "- Attention aux noms de variables. \n", + "*Faites valider votre script ainsi que son exécution*." + ] }, { "metadata": {}, @@ -126,50 +191,103 @@ { "metadata": {}, "cell_type": "markdown", - "source": "La seconde structure correspond au cas où le nombre de marches à gravir est connu. Si nous reprenons l'exemple du robot, et que vous connaissez à l'avance le nombre de marches à gravir il est donc facile de lui spécifier. \n**Attention toutefois** à la valeur saisie, si vous saisissez une valeur erronée les conséquences peuvent être dramatiques. Imaginez le robot voulant gravir une marche alors qu'il n'y en a plus ... \n\nLa boucle Pour permet de répéter une ou des insctructions un nombre défini de fois. En effet, le nombre de passage dans la boucle est égale à la valeur renseignée au moment de la définition de la boucle Pour. \nEn Python la boucle Pour se traduit par le mot-clé **for** ... \n\nIl existe deux manières de mettre en oeuvre une boucle *for*:\n* Effectuer une itération sur une collection d'objets. \n*Une collection aussi appelée séquence peut être une liste, un tuple, une chaîne de caractères, un dictionnaire.*\n* Effectuer une itération sur une suite de nombres. Dans ce cas il est possible de générer une suite de valeurs à partir d'un certain nombre, jusqu'à un certain autre avec une certain pas ou intervalle. " + "source": [ + "La seconde structure correspond au cas où le nombre de marches à gravir est connu. Si nous reprenons l'exemple du robot, et que vous connaissez à l'avance le nombre de marches à gravir il est donc facile de lui spécifier. \n", + "**Attention toutefois** à la valeur saisie, si vous saisissez une valeur erronée les conséquences peuvent être dramatiques. Imaginez le robot voulant gravir une marche alors qu'il n'y en a plus ... \n", + "\n", + "La boucle Pour permet de répéter une ou des instructions un nombre défini de fois. En effet, le nombre de passages dans la boucle est égale à la valeur renseignée au moment de la définition de la boucle Pour. \n", + "En Python la boucle Pour se traduit par le mot-clé **for** ... \n", + "\n", + "Il existe deux manières de mettre en oeuvre une boucle *for*:\n", + "* Effectuer une itération sur une collection d'objets. \n", + "*Une collection aussi appelée séquence peut être une liste, un tuple, une chaîne de caractères, un dictionnaire.*\n", + "* Effectuer une itération sur une suite de nombres. Dans ce cas, il est possible de générer une suite de valeurs à partir d'un certain nombre, jusqu'à un certain autre avec une certain pas ou intervalle. " + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T08:45:05.590165Z", + "start_time": "2024-10-08T08:45:05.558584Z" + } }, "cell_type": "code", "source": "#Syntaxe d'écriture\nfor variable in collection:\n instruction1", - "execution_count": null, - "outputs": [] + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'collection' is not defined", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mNameError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[101], line 2\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[38;5;66;03m#Syntaxe d'écriture\u001B[39;00m\n\u001B[0;32m----> 2\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m variable \u001B[38;5;129;01min\u001B[39;00m \u001B[43mcollection\u001B[49m:\n\u001B[1;32m 3\u001B[0m instruction1\n", + "\u001B[0;31mNameError\u001B[0m: name 'collection' is not defined" + ] + } + ], + "execution_count": 101 }, { "metadata": {}, "cell_type": "markdown", - "source": "A chaque tour de boucle *for*, la variable nommée *variable* va prendre les valeurs successives contenues dans la collection d'objets nommée *collection*. A chaque valeur prise, *instruction1* est exécutée. " + "source": "À chaque tour de boucle *for*, la variable nommée *variable* va prendre les valeurs successives contenues dans la collection d'objets nommée *collection*. À chaque valeur prise, *instruction1* est exécutée. " }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T08:45:05.664587Z", + "start_time": "2024-10-08T08:45:05.633995Z" + } }, "cell_type": "code", "source": "#Syntaxe d'écriture\nfor variable in range(debut, fin, pas):\n instruction1", - "execution_count": null, - "outputs": [] + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'debut' is not defined", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mNameError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[102], line 2\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[38;5;66;03m#Syntaxe d'écriture\u001B[39;00m\n\u001B[0;32m----> 2\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m variable \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28mrange\u001B[39m(\u001B[43mdebut\u001B[49m, fin, pas):\n\u001B[1;32m 3\u001B[0m instruction1\n", + "\u001B[0;31mNameError\u001B[0m: name 'debut' is not defined" + ] + } + ], + "execution_count": 102 }, { "metadata": {}, "cell_type": "markdown", - "source": "A chaque tout de boucle *for*, la variable nommée *variable* va prendre successives des valeurs numériques en commençant par une valeur égale à *debut*, jusqu'à une valeur *fin-1*, en effet la valeur de fin est **exclue**, avec un pas égale à *pas*. " + "source": "À chaque tout de boucle *for*, la variable nommée *variable* va prendre successives des valeurs numériques en commençant par une valeur égale à *debut*, jusqu'à une valeur *fin-1*, en effet la valeur de fin est **exclue**, avec un pas égale à *pas*. " }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T08:45:05.766636Z", + "start_time": "2024-10-08T08:45:05.761320Z" + } }, "cell_type": "code", "source": "#Exemple d'utilisation de la boucle for ...in \nphrase = \"Guido\"\nfor i in phrase:\n print(i)", - "execution_count": 16, "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "G\nu\ni\nd\no\n", - "name": "stdout" + "text": [ + "G\n", + "u\n", + "i\n", + "d\n", + "o\n" + ] } - ] + ], + "execution_count": 103 }, { "metadata": {}, @@ -178,18 +296,25 @@ }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T08:45:05.881137Z", + "start_time": "2024-10-08T08:45:05.876190Z" + } }, "cell_type": "code", "source": "#Exemple d'utilisation de la boucle for ... in range()\nfor i in range(2):\n print(i)", - "execution_count": 17, "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "0\n1\n", - "name": "stdout" + "text": [ + "0\n", + "1\n" + ] } - ] + ], + "execution_count": 104 }, { "metadata": {}, @@ -198,18 +323,25 @@ }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T08:45:05.920616Z", + "start_time": "2024-10-08T08:45:05.914798Z" + } }, "cell_type": "code", "source": "#Exemple2 d'utilisation de la boucle for ... in range()\nfor i in range(3, 5):\n print(i)", - "execution_count": 18, "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "3\n4\n", - "name": "stdout" + "text": [ + "3\n", + "4\n" + ] } - ] + ], + "execution_count": 105 }, { "metadata": {}, @@ -218,23 +350,63 @@ }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T08:45:06.040516Z", + "start_time": "2024-10-08T08:45:06.034051Z" + } }, "cell_type": "code", "source": "#Exemple3 d'utilisation de la boucle for ... in range()\nfor i in range(3, 13, 4):\n print(i)", - "execution_count": 19, "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "3\n7\n11\n", - "name": "stdout" + "text": [ + "3\n", + "7\n", + "11\n" + ] } - ] + ], + "execution_count": 106 }, { "metadata": {}, "cell_type": "markdown", - "source": "Dans le troisième et dernier exemple présenté ci-dessus, la variable *i* prend 3 valeurs en commençant par 3 (premier paramètre de *range()*) jusqu'à la valeur 13 exclue (second paramètre), avec un pas d'incrémentation égale à 4 (troisième parametre de *range()*). " + "source": [ + "Dans le troisième et dernier exemple présenté ci-dessus, la variable *i* prend 3 valeurs en commençant par 3 (premier paramètre de *range()*) jusqu'à la valeur 13 exclue (second paramètre), avec un pas d'incrémentation égale à 4 (troisième paramètre de *range()*).\n", + "\n", + "Avec l'instruction `enumerate`, il est possible de récupérer l'index et la valeur d'une collection." + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T08:45:06.120381Z", + "start_time": "2024-10-08T08:45:06.115025Z" + } + }, + "cell_type": "code", + "source": [ + "#Exemple d'utilisation de l'instruction enumerate\n", + "for index, value in enumerate(\"Guido\"):\n", + " print(\"Le caractère en position \", index, \" est \", value)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Le caractère en position 0 est G\n", + "Le caractère en position 1 est u\n", + "Le caractère en position 2 est i\n", + "Le caractère en position 3 est d\n", + "Le caractère en position 4 est o\n" + ] + } + ], + "execution_count": 107 }, { "metadata": {}, @@ -244,7 +416,7 @@ { "metadata": {}, "cell_type": "markdown", - "source": "**Table de multiplication** \nÉcrire un script Python faisant intervenir une boucle for, qui: \n* Demande à l'utilisateur de saisir un chiffre\n* Calcule et affiche toutes les valeurs comprises dans la table du chiffre choisit\n* Un message doit alors s'afficher (exemple si le chiffre choisit est 3): \n * 0 x 3 = 0\n * 1 x 3 = 3\n * ...\n * 10 x 3 = 30\n- Pensez à utiliser une boucle for\n- Attention aux commentaires\n- Attention aux noms de variables. \n*Faites valider votre script ainsi que son exécution*. " + "source": "" }, { "metadata": {}, @@ -267,6 +439,338 @@ "image/jpeg": "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" } } + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "***\n", + "### Les instructions `break` et `continue`\n", + "\n", + "#### `break`\n", + "\n", + "Il est possible d'interrompre une boucle *for* ou *while* avant qu'elle ne se termine normalement avec l'instruction `break`." + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T08:45:06.235038Z", + "start_time": "2024-10-08T08:45:06.227906Z" + } + }, + "cell_type": "code", + "source": [ + "# Exemple d'utilisation de l'instruction break qui calcul la dernière année bissextile\n", + "import datetime\n", + "\n", + "current_year = datetime.datetime.now().year\n", + "for year in range(current_year, current_year + 100):\n", + " if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:\n", + " break\n", + "print(\"La dernière année bissextile est: \", year)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "La dernière année bissextile est: 2024\n" + ] + } + ], + "execution_count": 108 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "#### ***Exercice 5***\n", + "\n", + "Écrire un script appelé `is_prime` qui prend en input un entier et calcul s'il\n", + "est premier ou non en utilisant l'instruction `break` dans une boucle.\n", + "\n", + "- Attention aux commentaires\n", + "- Attention aux noms de variables.\n", + "- Faites valider votre script ainsi que son exécution.\n", + "\n", + "#### `continue`\n", + "\n", + "L'instruction `continue` permet de passer à l'itération suivante d'une boucle *for* ou *while* sans exécuter les instructions qui suivent.\n", + "C'est une sorte de *go to*..." + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T08:45:06.283316Z", + "start_time": "2024-10-08T08:45:06.277432Z" + } + }, + "cell_type": "code", + "source": [ + "# Exemple d'utilisation de l'instruction continue\n", + "# Affiche les nombres impairs\n", + "for i in range(1, 11):\n", + " if i % 2 == 0:\n", + " continue\n", + " print(i)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "3\n", + "5\n", + "7\n", + "9\n" + ] + } + ], + "execution_count": 109 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "#### ***Exercice 6***\n", + "\n", + "Développer un script appelé `vowels_only.py` qui prend en input une chaîne de caractères\n", + "et affiche les voyelles uniquement.\n", + "\n", + "- Attention aux commentaires\n", + "- Attention aux noms de variables.\n", + "- Faites valider votre script ainsi que son exécution." + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "***\n", + "\n", + "### Les instructions `else` dans les boucles\n", + "\n", + "Il est possible d'ajouter une clause `else` à une boucle *for* ou *while*.\n", + "Cette clause est exécutée une fois que la boucle est terminée, mais pas si la boucle est interrompue par une instruction `break`.\n", + "Raymond Hettinger, un des développeurs principaux de Python, la trouve mal nommée et l'appelle *no break*!" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T08:45:06.385288Z", + "start_time": "2024-10-08T08:45:06.378713Z" + } + }, + "cell_type": "code", + "source": [ + "# Exemple d'utilisation de l'instruction else dans une boucle\n", + "# On essaie 3 fois de générer un nombre pair.\n", + "# Si aucun nombre pair n'est généré, on affiche un message\n", + "from random import randint # Méthode pour générer un nombre aléatoire\n", + "\n", + "for i in range(3): # On essaie 3 fois\n", + " if randint(1, 100) % 2 == 0: # De générer un nombre pair entre 1 et 100\n", + " print(\"Nombre pair généré: \", i)\n", + " break\n", + "else:\n", + " print(\"Aucun nombre pair n'a été généré\")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Aucun nombre pair n'a été généré\n" + ] + } + ], + "execution_count": 110 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "#### ***Exercice 7***\n", + "\n", + "Reprendre le script `vowels_only.py` et ajouter un message si aucune voyelle n'est trouvée.\n", + "\n", + "- Attention aux commentaires\n", + "- Attention aux noms de variables.\n", + "- Faites valider votre script ainsi que son exécution." + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### Trier une liste\n", + "\n", + "Il est possible de trier une liste avec la méthode `sort()` et la fonction `sorted()`.\n", + "\n", + "#### `sort()`\n", + "\n", + "Trie la liste directement." + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T08:45:06.483267Z", + "start_time": "2024-10-08T08:45:06.477626Z" + } + }, + "cell_type": "code", + "source": [ + "# Exemple de la méthode sort()\n", + "numbers = [4, 2, 1, 3]\n", + "numbers.sort()\n", + "print(numbers)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 4]\n" + ] + } + ], + "execution_count": 111 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "#### `sorted()`\n", + "\n", + "Retourne une nouvelle liste triée.\n" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T08:45:06.533632Z", + "start_time": "2024-10-08T08:45:06.527392Z" + } + }, + "cell_type": "code", + "source": [ + "# Exemple de la fonction sorted()\n", + "numbers = [4, 2, 1, 3]\n", + "sorted_numbers = sorted(numbers)\n", + "print(\"La liste retournée\", sorted_numbers)\n", + "print(\"La liste d'origine\", numbers)\n" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "La liste retournée [1, 2, 3, 4]\n", + "La liste d'origine [4, 2, 1, 3]\n" + ] + } + ], + "execution_count": 112 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### `map` et les compréhensions de liste\n", + "\n", + "Python est langage orienté objet, tout est objet en Python.\n", + "Mais, le succès grandissant de la programmation orientée fonctionnelle et la présence de l'instruction dans la plupart des langages modernes ont poussé les développeurs de Python à intégrer des fonctions haut niveau pour manipuler les collections comme `map`.\n", + "\n", + "On peut écrire des one liners pour manipuler des collections avec `map` et les compréhensions de liste.\n" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T08:45:06.639952Z", + "start_time": "2024-10-08T08:45:06.628666Z" + } + }, + "cell_type": "code", + "source": [ + "# Exemple de l'utilisation de map\n", + "# On met au carré chaque élément de la liste\n", + "numbers = [1, 2, 3, 4]\n", + "squared_numbers = list(map(lambda x: x**2, numbers))\n", + "print(squared_numbers)\n", + "# On a besoin de list() map est un objet qui n'affiche pas les valeurs\n", + "map_squared_numbers = map(lambda x: x**2, numbers)\n", + "print(\"Object \", map_squared_numbers, \"is of type: \", type(map_squared_numbers))\n", + "# Mais il est itérable\n", + "for number in map_squared_numbers:\n", + " print(number)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 4, 9, 16]\n", + "Object is of type: \n", + "1\n", + "4\n", + "9\n", + "16\n" + ] + } + ], + "execution_count": 113 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "Les compréhensions de list permettent aussi d'écrire des one liners pour manipuler des collections.\n", + "Mais avec la possibilité de filtrer les éléments." + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T08:45:06.750749Z", + "start_time": "2024-10-08T08:45:06.742645Z" + } + }, + "cell_type": "code", + "source": [ + "# Exemple de l'utilisation de map\n", + "# On met au carré chaque élément de la liste\n", + "numbers = [1, 2, 3, 4]\n", + "squared_numbers = [x**2 for x in numbers]\n", + "print(squared_numbers)\n", + "# On peut filtrer les éléments\n", + "even_numbers = [x for x in numbers if x % 2 == 0]\n", + "print(even_numbers)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 4, 9, 16]\n", + "[2, 4]\n" + ] + } + ], + "execution_count": 114 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "Les performances peuvent être meilleures avec `map` mais dans certains cas seulement, il faut voir au cas par cas.\n", + "Voir le ticket StackOverflow https://stackoverflow.com/questions/1247486/list-comprehension-vs-map" + ] } ], "metadata": { diff --git a/4_erreurs_exceptions.ipynb b/4_erreurs_exceptions.ipynb new file mode 100644 index 0000000..00e8bb6 --- /dev/null +++ b/4_erreurs_exceptions.ipynb @@ -0,0 +1,533 @@ +{ + "cells": [ + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "# Erreurs et Exceptions\n", + "\n", + "En programmation, il y a deux types d'erreurs : les erreurs de syntaxe et les exceptions." + ], + "id": "83138be94230136a" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "***\n", + "## Erreurs de syntaxe\n", + "Les erreurs de syntaxe sont des erreurs de frappe dans le code, qui empêchent le programme de s'exécuter.\n", + "Il n'y aucun moyen de passer outre ces erreurs, il faut les corriger." + ], + "id": "71064e7cf29e155f" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T13:15:31.008382Z", + "start_time": "2024-10-08T13:15:31.001583Z" + } + }, + "cell_type": "code", + "source": [ + "# Exemple d'erreur de syntaxe\n", + "var11 = \"Bonjour\"\n", + "try:\n", + " if var11 == \"Bonjour\":\n", + " print(\"Bonjour\")\n", + "except IndentationError as e:\n", + " print(e)\n", + "print(\"Après l'erreur!\")" + ], + "id": "b3926b2de83e1f95", + "outputs": [ + { + "ename": "IndentationError", + "evalue": "expected an indented block after 'if' statement on line 4 (2368664154.py, line 5)", + "output_type": "error", + "traceback": [ + "\u001B[0;36m Cell \u001B[0;32mIn[17], line 5\u001B[0;36m\u001B[0m\n\u001B[0;31m print(\"Bonjour\")\u001B[0m\n\u001B[0m ^\u001B[0m\n\u001B[0;31mIndentationError\u001B[0m\u001B[0;31m:\u001B[0m expected an indented block after 'if' statement on line 4\n" + ] + } + ], + "execution_count": 17 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### Exercice 1\n", + "\n", + "Trouver un autre exemple d'erreur de syntaxe qui empêche le programme de s'exécuter." + ], + "id": "4eb351beb2190803" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "Il n'y a aucune exécution après une erreur de syntaxe.\n", + "Même si cette dernière est dans une exception.\n", + "\n", + "Vérifions maintenant le code erreur si ce code est exécuté dans un script:\n", + "```bash\n", + "$ python3 <\", line 5\n", + " print(\"Bonjour\")\n", + " ^\n", + "IndentationError: expected an indented block after 'if' statement on line 4\n", + "(venv) chrichri@chrichri-HKD-WXX:~/Documents/Serendip/C12$ echo \"Last return code is $?\"\n", + "$ echo \"Last return code is $?\"\n", + "Last return code is 1\n", + "```\n", + "\n", + "Le programme a terminé en erreur, avec un code de retour 1." + ], + "id": "7c743a55c97b8eb" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "***\n", + "## Exceptions\n", + "\n", + "Une exception peut être levée à tout moment dans un programme.\n", + "Mais il est possible de les intercepter et de les traiter.\n", + "Cette interception se fait avec les mots clé `try` et `except`.\n", + "L'équivalent du plus fameux `try` et `catch` dans les autres langages de programmation.\n", + "\n", + "Il est possible de lever une exception avec le mot clé `raise`.\n", + "\n", + "Et de créer sa propre exception par héritage de la classe exception.\n", + "\n", + "### Les exceptions built-in de Python\n", + "\n", + "Selon la documentation https://docs.python.org/3/library/exceptions.html#exception-hierarchy, il existe de nombreuses exceptions built-in dans Python.\n", + "\n", + "```\n", + "BaseException\n", + " ├── BaseExceptionGroup\n", + " ├── GeneratorExit\n", + " ├── KeyboardInterrupt\n", + " ├── SystemExit\n", + " └── Exception\n", + " ├── ArithmeticError\n", + " │ ├── FloatingPointError\n", + " │ ├── OverflowError\n", + " │ └── ZeroDivisionError\n", + " ├── AssertionError\n", + " ├── AttributeError\n", + " ├── BufferError\n", + " ├── EOFError\n", + " ├── ExceptionGroup [BaseExceptionGroup]\n", + " ├── ImportError\n", + " │ └── ModuleNotFoundError\n", + " ├── LookupError\n", + " │ ├── IndexError\n", + " │ └── KeyError\n", + " ├── MemoryError\n", + " ├── NameError\n", + " │ └── UnboundLocalError\n", + " ├── OSError\n", + " │ ├── BlockingIOError\n", + " │ ├── ChildProcessError\n", + " │ ├── ConnectionError\n", + " │ │ ├── BrokenPipeError\n", + " │ │ ├── ConnectionAbortedError\n", + " │ │ ├── ConnectionRefusedError\n", + " │ │ └── ConnectionResetError\n", + " │ ├── FileExistsError\n", + " │ ├── FileNotFoundError\n", + " │ ├── InterruptedError\n", + " │ ├── IsADirectoryError\n", + " │ ├── NotADirectoryError\n", + " │ ├── PermissionError\n", + " │ ├── ProcessLookupError\n", + " │ └── TimeoutError\n", + " ├── ReferenceError\n", + " ├── RuntimeError\n", + " │ ├── NotImplementedError\n", + " │ ├── PythonFinalizationError\n", + " │ └── RecursionError\n", + " ├── StopAsyncIteration\n", + " ├── StopIteration\n", + " ├── SyntaxError\n", + " │ └── IndentationError\n", + " │ └── TabError\n", + " ├── SystemError\n", + " ├── TypeError\n", + " ├── ValueError\n", + " │ └── UnicodeError\n", + " │ ├── UnicodeDecodeError\n", + " │ ├── UnicodeEncodeError\n", + " │ └── UnicodeTranslateError\n", + " └── Warning\n", + " ├── BytesWarning\n", + " ├── DeprecationWarning\n", + " ├── EncodingWarning\n", + " ├── FutureWarning\n", + " ├── ImportWarning\n", + " ├── PendingDeprecationWarning\n", + " ├── ResourceWarning\n", + " ├── RuntimeWarning\n", + " ├── SyntaxWarning\n", + " ├── UnicodeWarning\n", + " └── UserWarning\n", + "```\n", + "Nous n'allons pouvoir les traiter toutes, veuillez vous référer à la documentation pour plus d'informations.\n", + "**RTFM**! Comme on dit...\n", + "\n", + "Built-in veut dire qu'on peut les utiliser à tout moment, sans les importer.\n", + "\n", + "⚠️ Ce sont toutes des exceptions, même si elles finissent par `Warning`, `Error` ou `Exception`." + ], + "id": "f28a02845f5b5c82" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T13:15:31.073029Z", + "start_time": "2024-10-08T13:15:31.066608Z" + } + }, + "cell_type": "code", + "source": [ + "# Exemple d'exception\n", + "\n", + "# Lire un fichier qui n'existe pas et faire un display de l'erreur en standard erreur\n", + "import sys\n", + "\n", + "try:\n", + " with open('data_20991231.csv') as f:\n", + " content = f.read()\n", + "except FileNotFoundError as e:\n", + " print(e, file=sys.stderr)\n", + " print(\"No data, leaving program\", file=sys.stderr)\n", + " exit(0)" + ], + "id": "5a07053ac4ce88b", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Errno 2] No such file or directory: 'data_20991231.csv'\n", + "No data, leaving program\n" + ] + } + ], + "execution_count": 18 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T13:15:31.092070Z", + "start_time": "2024-10-08T13:15:31.086601Z" + } + }, + "cell_type": "code", + "source": [ + "# Dans le cas d'opération arithmétique, controller une division par zéro\n", + "import sys\n", + "\n", + "try:\n", + " 1 / 0\n", + "except ZeroDivisionError as e:\n", + " print(e, file=sys.stderr)\n", + " print(\"Check the input data\", file=sys.stderr)\n", + " exit(1)" + ], + "id": "66f02b87255680be", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "division by zero\n", + "Check the input data\n" + ] + } + ], + "execution_count": 19 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "On peut aussi intercepter plusieurs exceptions en même temps:", + "id": "4801aad6b10eae08" + }, + { + "metadata": { + "jupyter": { + "is_executing": true + } + }, + "cell_type": "code", + "source": [ + "# Exemple d'exception multiple\n", + "import sys\n", + "import os\n", + "\n", + "try:\n", + " os.chdir('financial')\n", + " # Read file in a directory\n", + " with open('data_20991231.csv') as f:\n", + " content = f.read()\n", + "except (NotADirectoryError, FileNotFoundError) as e:\n", + " print(e, file=sys.stderr)\n", + " print(\"No data, leaving program\", file=sys.stderr)" + ], + "id": "b97b8749d4a85349", + "outputs": [], + "execution_count": null + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "Ou les intercepter les unes à la suite des autres:", + "id": "57da9e39f78cca78" + }, + { + "metadata": { + "jupyter": { + "is_executing": true + } + }, + "cell_type": "code", + "source": [ + "# Exemple d'exception multiple\n", + "import sys\n", + "import os\n", + "\n", + "try:\n", + " os.chdir('financial')\n", + " # Read file in a directory\n", + " with open('data_20991231.csv') as f:\n", + " content = f.read()\n", + "except NotADirectoryError as e:\n", + " print(e, file=sys.stderr)\n", + " exit(0)\n", + "except FileNotFoundError as e:\n", + " print(e, file=sys.stderr)\n", + " exit(1)" + ], + "id": "905b2cd80af91f73", + "outputs": [], + "execution_count": null + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "On peut intercepter de la même manière une exception parente, donc plus générique.\n", + "Une exception parente est dont a hérité directement ou indirectement une exception.\n", + "\n", + "Par exemple, on voit que `FileNotFoundError` et `NotADirectory` héritent de `OSError`:\n", + "\n", + "```bash\n", + "BaseException\n", + "...\n", + " └── Exception\n", + "...\n", + " ├── OSError\n", + "...\n", + " │ ├── FileExistsError\n", + " │ ├── FileNotFoundError\n", + " │ ├── InterruptedError\n", + " │ ├── IsADirectoryError\n", + "...\n", + "```\n", + "\n", + "On peut donc réécrire le code précédent de la manière suivante:" + ], + "id": "a6e8b7d19d682fcd" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T13:15:33.201568Z", + "start_time": "2024-10-08T13:15:33.194014Z" + } + }, + "cell_type": "code", + "source": [ + "# Exemple d'exception multiple\n", + "import sys\n", + "import os\n", + "\n", + "try:\n", + " os.chdir('financial')\n", + " # Read file in a directory\n", + " with open('data_20991231.csv') as f:\n", + " content = f.read()\n", + "except OSError as e:\n", + " print(e, file=sys.stderr)\n", + " print(\"No data, leaving program\", file=sys.stderr)" + ], + "id": "dcfc367aedca2f13", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Errno 2] No such file or directory: 'financial'\n", + "No data, leaving program\n" + ] + } + ], + "execution_count": 1 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "⚠️ Cependant, il est recommandé d'être le plus spécifique possible dans le traitement des exceptions.", + "id": "170b0e6c54eed152" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "Si aucune Exception n'est passée à la clause `except`, alors toutes les exceptions seront interceptées.\n", + "C'est une sorte de wildcard:" + ], + "id": "fd956b1fe64209e9" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T13:15:33.213083Z", + "start_time": "2024-10-08T13:15:33.204825Z" + } + }, + "cell_type": "code", + "source": [ + "try:\n", + " f = open('my_file.txt')\n", + " s = f.readline()\n", + " i = int(s.strip())\n", + "except IOError as e:\n", + " print(\"I/O error(%s): %s\" % (e.errno, e.strerror), file=sys.stderr)\n", + " print(e, file=sys.stderr)\n", + "except ValueError:\n", + " print(\"Could not convert data to an integer.\", file=sys.stderr)\n", + "except:\n", + " print(\"Unexpected error:\", sys.exc_info()[0], file=sys.stderr)\n", + " raise\n" + ], + "id": "ccd27e5b0e917dcc", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "I/O error(2): No such file or directory\n", + "[Errno 2] No such file or directory: 'myfile.txt'\n" + ] + } + ], + "execution_count": 2 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "⚠️ On remarque ici que les exceptions peuvent avoir des attributs particuliers, comme `errno` et `strerror` pour `IOError`.", + "id": "b2f870b5e8bd38" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### Créer sa propre exception\n", + "\n", + "Dans de nombreux certains cas, il est nécessaire d'avoir une exception propre à son application." + ], + "id": "934a37bcdd5b8ecf" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T13:15:33.221653Z", + "start_time": "2024-10-08T13:15:33.215531Z" + } + }, + "cell_type": "code", + "source": [ + "import sys\n", + "\n", + "\n", + "class IsNotOddException(Exception):\n", + " pass # Rien à ajouter, on hérite de la classe Exception\n", + "\n", + "\n", + "for i in range(10):\n", + " try:\n", + " if i % 2 == 0:\n", + " raise IsNotOddException(f\"{i} is not odd\")\n", + " except IsNotOddException as e:\n", + " print(e, file=sys.stderr)" + ], + "id": "8014637af8c2a5db", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "0 is not odd\n", + "2 is not odd\n", + "4 is not odd\n", + "6 is not odd\n", + "8 is not odd\n" + ] + } + ], + "execution_count": 3 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### Exercice 2\n", + "\n", + "Créer une exception `IsEvenException` qui sera levée si un nombre passé en input est pair dans un algorithme qui doit vérifier si un nombre est premier.\n", + "Une autre appelée `IsNegativeException` si le nombre est négatif.\n", + "Développer cela dans un script appelé `is_prime.py`, il prend en input un entier print si le nombre positif et impair est premier ou non dans le terminal.\n", + "\n", + "- Attention aux commentaires\n", + "- Attention aux noms de variables. \n", + "*Faites valider votre script ainsi que son exécution*. " + ], + "id": "fbb0f76853c9565f" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/5_fonctions.ipynb b/5_fonctions.ipynb new file mode 100644 index 0000000..15628d3 --- /dev/null +++ b/5_fonctions.ipynb @@ -0,0 +1,1121 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Programmation Python 3 - Les fonctions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Définition" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "La manière dont un développeur va écrire son code est un paradigme de programmation. Ainsi, un paradigme de programmation est une approche logique qu'un développeur va adopter pour résoudre son problème. \n", + "\n", + "Depuis que vous travaillez en langage Python, vous utilisez un paradigme impératif, en effet les étapes d'instruction se suivent jusqu'à aboutir au résultat attendu. Cette méthode de résolution consiste à réaliser des instructions les unes à la suite des autres. C'est une approche efficace pour les programmes/scripts courts avec peu d'instructions. Le code impératif (aussi appelé code procédural) n'est pas réutilisable. \n", + "\n", + "Ainsi, il existe d'autres paradigmes permettant de réaliser les instructions de la manière dont nous les souhaitons, comme par exemple, le paradigme objet ou le paradigme fonctionnel. \n", + "\n", + "- La programmation orientée objet consiste à designer son code sous forme d'objets ayant des propriétés (appelées attributs) et des capacités d'action (appelées méthodes) qui interagissent entre eux plutôt qu'une séquence d'instructions. \n", + " \n", + "- La programmation fonctionnelle permet de décomposer un problème en un ensemble de fonctions. Dans l'idéal, les fonctions produisent des sorties à partir des entrées et ne possèdent pas d'état interne qui soit susceptible de modifier la sortie pour une entrée donnée. Le paradigme fonctionnel cherche à éviter au maximum les effets de bord, en programmation fonctionnelle, on va éviter de modifier les valeurs associées à des variables globales. \n", + "\n", + "Dans les deux cas, les objets ou les fonctions sont des briques réutilisables qui rendent le pool code modulaire et découplé." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "En programmation, une approche efficace d'un problème complexe revient à le décomposer en plusieurs sous-problèmes plus simples qui peuvent eux-mêmes être décomposés à leur tout jusqu'à aboutir à un des sous-sous-sous...problèmes simples. \n", + "Il est également fréquent de vouloir répéter une même séquence d'instructions, à plusieurs reprises sans pour autant avoir à réécrire les instructions concernées, c'est le rôle des **fonctions**. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Généralités" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "En plus de permettre une répétition d'instructions autant de fois que désiré, les fonctions rendent le code plus lisible et plus clair. \n", + "Vous avez déjà utilisé des fonctions built-in, c.-à-d. préprogrammées telles que `len`, `range` ou même la méthode `randint` du module `random`. \n", + "Lors de l'utilisation de ces fonctions vous avez passé aucune, une ou plusieurs variables ou valeurs entre les parenthèses, comme par exemple `len(liste)`, `range(2, 9, 2)` ou `randint(1, 100)`. Ces variables ou valeurs sont appelées des **arguments** et sont nécessaires à la fonction afin que celle-ci s'exécute correctement. Les arguments peuvent être de n'importe quel type et sont propres à la fonction utilisée. Il est possible qu'une fonction n'ait pas besoin d'arguments. \n", + "\n", + "Après l'exécution de la fonction, celle-ci peut renvoyer aucune, une ou plusieurs variables ou valeurs en sortie comme par exemple `len(liste)` qui renvoie une donnée numérique de type entier égale à la longueur de l'argument, ici `liste`, ou `liste.append(4)` qui ajoute l'argument à la fin de `liste` mais ne renvoie rien. \n", + "\n", + "En général, une fonction effectue une tâche **unique** et **précise**. Il vaut mieux décomposer le programme en de nombreuses petites sous-tâches appelées fonctions plutôt que de créer moitié moins de fonctions qui à elles-seules réaliser plusieurs tâches.\n", + "Le code en sera d'autant plus lisible et clair.\n", + "C'est le concept de responsabilité unique en architecture logicielle. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Déclaration" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Pour pouvoir utiliser une fonction, il faut réaliser deux actions essentielles :\n", + "1. Déclaration de la fonction\n", + "2. Appel de la fonction \n", + "\n", + "L'appel de la fonction peut être réalisé dans la fonction elle-même, dans une autre fonction, ou dans le programme principal (il s'agit de la partie du code qui est exécuté quand le programme est lancé. Le programme principal se situe après les définitions de fonctions. \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Pour déclarer ou définir une fonction, il faut utiliser le mot-clé **def** suivi du nom que l'on souhaite donner à la fonction. **Attention, comme pour les noms de variables il est recommandé de donner des noms significatifs**. \n", + "\n", + "La syntaxe d'écriture ppur déclarer une fonction est la suivante: " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:23.160378Z", + "start_time": "2024-10-08T19:43:23.153525Z" + } + }, + "source": [ + "def nom_significatif_de_la_fonction_avec_verbe(argument1, argument2, ...):\n", + " instruction1\n", + " instruction2\n", + " instruction3\n", + " ..." + ], + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (1806011812.py, line 1)", + "output_type": "error", + "traceback": [ + "\u001B[0;36m Cell \u001B[0;32mIn[5], line 1\u001B[0;36m\u001B[0m\n\u001B[0;31m def nom_significatif_de_la_fonction_avec_verbe(argument1, argument2, ...):\u001B[0m\n\u001B[0m ^\u001B[0m\n\u001B[0;31mSyntaxError\u001B[0m\u001B[0;31m:\u001B[0m invalid syntax\n" + ] + } + ], + "execution_count": 5 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Il est important de penser aux éléments suivants lors de la définition d'une fonction: \n", + "* Ne pas oublier le mot-clé **def** en début de la définition\n", + "* Donner un nom significatif à la fonction\n", + "* Ne pas oublier les parenthèses même s'il n'y pas d'arguments !\n", + "* Ne pas oublier les **:** à la fin de l'instruction de définition\n", + "* Ne pas oublier l'**indentation** pour les instructions qui composent la fonction. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:23.327860Z", + "start_time": "2024-10-08T19:43:23.322566Z" + } + }, + "source": [ + "#Exemple de déclaration d'une fonction sans argument\n", + "#----- Début Declaration de fonctions -----\n", + "def message_de_bienvenue():\n", + " print(\"Bienvenue dans le chapitre sur les fonctions\")\n", + "\n", + "#----- Fin Declaration de fonctions -----" + ], + "outputs": [], + "execution_count": 6 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "En exécutant la cellule ci-dessus on constate que rien ne se passe, en effet seule la définition de la fonction a été réalisée. L'appel de la fonction est absent. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:23.357344Z", + "start_time": "2024-10-08T19:43:23.351510Z" + } + }, + "source": [ + "#Exemple de déclaration d'une fonction sans argument\n", + "#----- Début Declaration de fonctions -----\n", + "def message_de_bienvenue():\n", + " print(\"Bienvenue dans le chapitre sur les fonctions\")\n", + "\n", + "\n", + "#----- Fin Declaration de fonctions -----\n", + "\n", + "#----- Début Programme Principal -----\n", + "message_de_bienvenue()\n", + "#----- Fin Programme Principal -----" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Bienvenue dans le chapitre sur les fonctions\n" + ] + } + ], + "execution_count": 7 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Après appel de la fonction, on constate bien son exécution. \n", + "Lors de l'appel de la fonction, il faut veiller à :\n", + "* Appeler la fonction avec son nom correctement saisi\n", + "* Ne pas oublier les parenthèses même s'il n'y a pas d'argument\n", + "* S'il y en a, ne pas oublier les arguments dans les parenthèses" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:23.558656Z", + "start_time": "2024-10-08T19:43:23.552398Z" + } + }, + "source": [ + "#Exemple de déclaration d'une fonction avec arguments\n", + "#----- Début Declaration de fonctions -----\n", + "def message_de_bienvenue(message, repetitions):\n", + " for i in range(repetitions):\n", + " print(message)\n", + "\n", + "\n", + "#----- Fin Declaration de fonctions -----\n", + "\n", + "#----- Début Programme Principal -----\n", + "mon_message = \"Bonjour\"\n", + "nb_repetitions = 3\n", + "message_de_bienvenue(mon_message, nb_repetitions)\n", + "#----- Fin Programme Principal -----" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Bonjour\n", + "Bonjour\n", + "Bonjour\n" + ] + } + ], + "execution_count": 8 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Les exemples que nous venons de traiter seront plus considérés comme des ***procédures*** et non de \"vraies\" fonctions. En effet, une fonction doit renvoyer une valeur lorsque celle-ci termine de s'exécuter, ce qui engendre que dans le programme principal, la valeur retournée doit être assignée à une variable. \n", + "\n", + "C'est l'instruction `return` qui permet de renvoyer une ou plusieurs valeurs. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:23.602480Z", + "start_time": "2024-10-08T19:43:23.596384Z" + } + }, + "source": [ + "# Exemple de déclaration d'une fonction retournant une valeur\n", + "# ----- Début Declaration de fonctions -----\n", + "def additionner(nb1, nb2=30.0):\n", + " res = nb1 + nb2\n", + " return res\n", + "\n", + "\n", + "# ----- Fin Declaration de fonctions -----\n", + "\n", + "# ----- Début Programme Principal -----\n", + "val1 = 37.19\n", + "val2 = 87.34\n", + "ex1_somme = additionner(val1, val2)\n", + "print(ex1_somme)\n", + "ex2_somme = additionner(val1)\n", + "print(ex2_somme)\n", + "# ----- Fin Programme Principal -----" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "124.53\n", + "67.19\n" + ] + } + ], + "execution_count": 9 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dans l'exemple présenté ci-dessus, on constate donc que la variable `ex1_somme` prend la valeur retournée par le premier appel de fonction de `additionner` avec les valeurs `37.19` et `87.34`. \n", + "Pour la variable `ex2_somme` celle-ci prend la valeur retournée par le second appel de fonction mais où un seul paramètre n'est spécifié alors que deux sont nécessaires comme mentionnée dans la définition de la fonction. \n", + "**Dans la definition d'une fonction, il est possible de définir une valeur par défaut des arguments**. Cette valeur définit par défaut n'est pas prioritaire et est ainsi ignorée lorsque la valeur est spécifiée lors de l'appel de fonction. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "Afin de rendre le code plus lisible et clair, il est possible d'annoter les fonctions. Pour cela, chaque paramètre va être suivi de son type, ainsi que le type retourné par la fonction à la fin de son exécution. " + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:23.727337Z", + "start_time": "2024-10-08T19:43:23.720094Z" + } + }, + "source": [ + "# Exemple de déclaration d'une fonction avec annotations\n", + "# ----- Début Declaration de fonctions -----\n", + "def additionner(nb1: float, nb2: float = 30.0) -> float:\n", + " res = nb1 + nb2\n", + " return res\n", + "\n", + "\n", + "# ----- Fin Declaration de fonctions -----\n", + "\n", + "# ----- Début Programme Principal -----\n", + "val1 = 37.19\n", + "val2 = 87.34\n", + "ex1_somme = additionner(val1, val2)\n", + "print(ex1_somme)\n", + "ex2_somme = additionner(val1)\n", + "print(ex2_somme)\n", + "# ----- Fin Programme Principal -----" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "124.53\n", + "67.19\n" + ] + } + ], + "execution_count": 10 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dans l'exemple ci-dessus, on constate donc que les deux arguments doivent être tous les deux type `float` (il faut séparer le nom de la variable du type avec `:`). Le type retourné par la fonction doit être spécifié entre les arguments et le caractère `:` en utilisant les caractères `->` suivi du type. Ce n'est qu'un _type hinting_ une indication, elle peut être fausse.\n", + "***Attention, l'annotation de fonctions est optionnelle, ainsi lors de l'appel de la fonction le paramètre n'est pas du même type que celui mentionné dans la définition de la fonction, aucune erreur ne sera généré. C'est à la charge du développeur de vérifier que les types des paramètres sont bien conformes***. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Variables globales et locales" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "La portée des variables est un point important dans le paradigme fonctionnel. En effet, en fonction de l'endroit dans le script où les variables sont définies va être déterminant sur leur utilisation. En Python, une variable peut avoir une portée (espaces dans lesquels la variable est accessible) **locale** ou une portée **globale**. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Une variable **globale** peut être accessible n'importe où dans le script. \n", + "- Une variable **locale** est accessible uniquement à l'intérieur d'un bloc de code. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**En Python, si une variable n'est pas modifiée dans une fonction mais seulement lue, elle est implicitement considérée comme globale. Si une valeur lui est affectée, elle est considérée comme locale (sauf si elle est explicitement déclarée globale)**. \n", + "\n", + "L'exemple ci-dessous illustre la règle présentée ci-dessus : " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:23.755701Z", + "start_time": "2024-10-08T19:43:23.748293Z" + } + }, + "source": [ + "# Exemple de déclaration d'une variable globale\n", + "# ----- Début déclaration variable globale -----\n", + "res = 0\n", + "\n", + "\n", + "# ----- Fin déclaration variable globale -----\n", + "\n", + "# ----- Début Declaration de fonctions -----\n", + "def additionner(nb1: float, nb2: float = 30.0) -> float:\n", + " res = nb1 + nb2\n", + " return res\n", + "\n", + "\n", + "# ----- Fin Declaration de fonctions -----\n", + "\n", + "# ----- Début Programme Principal -----\n", + "val1 = 37.19\n", + "val2 = 87.34\n", + "ex1_somme = additionner(val1, val2)\n", + "print(ex1_somme)\n", + "ex2_somme = additionner(val1)\n", + "print(ex2_somme)\n", + "print(\"Affichage valeur de la variable globale res: \", res)\n", + "# ----- Fin Programme Principal -----" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "124.53\n", + "67.19\n", + "Affichage valeur de la variable globale res: 0\n" + ] + } + ], + "execution_count": 11 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dans l'exemple on constate que la variable `res` est déclarée en variable globale. Dans la fonction `additionner`, la variable `res` se voit affecter une valeur. Cette variable porte le même nom que la variable globale. La variable `res` définit dans la fonction est donc une variable locale et n'est accessible qu'au sein de cette fonction. Pour preuve, à la fin du programme un affichage de la variable `res` est demandé et c'est la valeur 0 qui est affichée, cette valeur étant celle assignée par défaut au moment de la déclaration de la variable globale, la valeur n'a donc pas été modifiée au sein de la fonction. \n", + "\n", + "Si le but est de modifier la valeur de la variable globale, il faut alors le déclarer explicitement comme présenté ci-dessous: " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:23.848772Z", + "start_time": "2024-10-08T19:43:23.839879Z" + } + }, + "source": [ + "# Exemple de déclaration d'une variable globale\n", + "# ----- Début déclaration variable globale -----\n", + "res = 0\n", + "\n", + "\n", + "# ----- Fin déclaration variable globale -----\n", + "\n", + "# ----- Début Declaration de fonctions -----\n", + "def additionner(nb1: float, nb2: float = 30.0) -> float:\n", + " global res\n", + " res = nb1 + nb2\n", + " return res\n", + "\n", + "\n", + "# ----- Fin Declaration de fonctions -----\n", + "\n", + "# ----- Début Programme Principal -----\n", + "val1 = 37.19\n", + "val2 = 87.34\n", + "ex1_somme = additionner(val1, val2)\n", + "print(ex1_somme)\n", + "ex2_somme = additionner(val1)\n", + "print(ex2_somme)\n", + "print(\"Affichage valeur de la variable globale res: \", res)\n", + "# ----- Fin Programme Principal -----" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "124.53\n", + "67.19\n", + "Affichage valeur de la variable globale res: 67.19\n" + ] + } + ], + "execution_count": 12 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "L'instruction `global` permet de spécifier que la variable qui suit est une variable globale, pour preuve à la fin de l'exécution du script on constate que la valeur finale de la variable globale `res` n'est plus égale à 0 mais au résultat de l'addition opérée au sein de la fonction. " + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "Toutefois, l'utilisation de l'instruction `global` est déconseillée car ce n'est pas une bonne pratique et doit dans la limite du possible être évitée. Si le but est de modifier le contenu d'une variable globale, il est préférable d'utiliser la valeur retournée par la fonction.\n" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Docstring" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Un script Python sera plus souvent lu qu'écrit, en ce sens il est primordial de rendre son contenu clair, lisible afin de faciliter sa lecture et sa compréhension. En plus des noms de variables, les noms des fonctions qui doivent être significatifs, il est opportun de mettre des commentaires à tout script Python ainsi qu'une documentation à chaque fonction déclarée. Cette documentation se présente sous la forme de *docstring*. Cette documentation se présente sous la forme d'un paragraphe entouré des caractères *\"\"\"* et se situe au tout début de la définition de la fonction. \n", + "Il s'agit d'une explication textuelle et doit a minima contenir les éléments suivants : \n", + "- Une phrase présentant l'objectif de la fonction. Cette phrase doit permettre de répondre à la question \"A quoi sert cette fonction ?\". \n", + "- Préciser les types de données (arguments) ainsi que leur utilité. \n", + "- Préciser les types de sorties (données retournées) ainsi que leur utilité. \n", + "\n", + "Un exemple ci-dessous vous présentant un format RST (le plus classique) de docstring : " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:23.882821Z", + "start_time": "2024-10-08T19:43:23.864494Z" + } + }, + "source": [ + "# Exemple de déclaration d'une variable globale\n", + "# ----- Début déclaration variable globale -----\n", + "res = 0\n", + "\n", + "\n", + "# ----- Fin déclaration variable globale -----\n", + "\n", + "# ----- Début Declaration de fonctions -----\n", + "def additionner(nb1: float, nb2: float = 30.0) -> float:\n", + " \"\"\"Calcul d'une somme entre deux nombres\n", + " \n", + " :param nb1: Premier nombre à additionner, type float\n", + " :param nb2: Second nombre à additionner, type float (defaut: 30.0)\n", + " \n", + " return res: Résultat de l'addition, type float\n", + " \"\"\"\n", + " res = nb1 + nb2\n", + " return res\n", + "\n", + "\n", + "# ----- Fin Declaration de fonctions -----\n", + "\n", + "# ----- Début Programme Principal -----\n", + "val1 = 37.19\n", + "val2 = 87.34\n", + "ex1_somme = additionner(val1, val2)\n", + "print(ex1_somme)\n", + "ex2_somme = additionner(val1)\n", + "print(res)\n", + "print(\"Affichage valeur de la variable globale res: \", res)\n", + "# ----- Fin Programme Principal -----" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "124.53\n", + "0\n", + "Affichage valeur de la variable globale res: 0\n" + ] + } + ], + "execution_count": 13 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***\n", + "#### ***Exercice 1***" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***Des lettres et des lettres !*** \n", + "\n", + "Écrire un script Python en adoptant le paradigme fonctionnel et permettant au joueur de jouer à une version simplifiée du Scrabble. \n", + "Le joueur se voit attribuer 7 lettres au hasard. Ce dernier doit ensuite former un mot avec les lettres à sa disposition. Si le mot proposé par le joueur est possible, c'est-à-dire qu'il peut être écrit à partir des lettres à sa disposition, le joueur gagne un nombre de points égal au nombre de lettres du mot. Dans le cas contraire si pas de proposition ou si le mot ne peut pas être écrit dans sa totalité avec les lettres à la disposition du joueur, ce dernier se voit attribué le score de 0. \n", + "\n", + "*Exemple:* \n", + "- Lettres à la disposition du joueur : NBJORUO\n", + "- Proposition du joueur : JOUR -> Score = 4\n", + "- Autre proposition du joueur : SALUT -> Score = 0 \n", + " \n", + "1. Attention aux commentaires\n", + "2. Attention aux docstring\n", + "3. Attention aux noms de variables. \n", + "\n", + "*Faites valider votre script ainsi que son exécution.* \n", + "***" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### ***Exercice 2***" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "En vous appuyant sur le script de l'exercice 1, écrire un script Python en adoptant le paradigme fonctionnel et permettant de jouer au scrabble. \n", + "Les valeurs des lettres sont les suivantes: \n", + "- 0 point: Joker (permet de remplacer n'importe quelle lettre)\n", + "- 1 point: E, A, I, N, O, R, S, T, U, L\n", + "- 2 points: D, G, M\n", + "- 3 points: B, C, P\n", + "- 4 points: F, H, V\n", + "- 8 points: J, Q\n", + "- 10 points: K, W, X, Y, Z \n", + "\n", + "1. Attention aux commentaires\n", + "1. Attention aux docstring\n", + "1. Attention aux noms de variables. \n", + "\n", + "*Faites valider votre script ainsi que son exécution.*" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "***\n", + "## Les fonctions lambda\n", + "\n", + "Inspirée de la programmation fonctionnelle, cette syntaxe permet de déclarer une fonction simple." + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:23.977082Z", + "start_time": "2024-10-08T19:43:23.971566Z" + } + }, + "cell_type": "code", + "source": [ + "is_even = lambda n: n % 2 == 0\n", + "print(\"Is 5 even: \", is_even(5))\n", + "is_odd = lambda n: not is_even(n)\n", + "print(\"Is 5 odd: \", is_odd(5))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Is 5 even: False\n", + "Is 5 odd: True\n" + ] + } + ], + "execution_count": 14 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "Toujours inspirée de la programmation fonctionnelle, cette syntaxe est souvent utilisée avec `map`, `functools.reduce`, `functools.filter`." + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:23.999418Z", + "start_time": "2024-10-08T19:43:23.992806Z" + } + }, + "cell_type": "code", + "source": [ + "# Liste les booléens jusqu'à 10\n", + "print(list(map(is_odd, range(10))))\n", + "# Filtre les nombres pairs\n", + "# map est built-in alors que filter et reduce font partie d'une libraire dédiée,\n", + "# functools (https://docs.python.org/fr/3/library/functools.html) à programmation fonctionnelle.\n", + "print(list(filter(is_odd, range(10))))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[False, True, False, True, False, True, False, True, False, True]\n", + "[1, 3, 5, 7, 9]\n" + ] + } + ], + "execution_count": 15 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### Exercice 3\n", + "\n", + "Écrire une fonction lambda qui donne la racine d'une liste de nombres " + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### `functools.partial`\n", + "\n", + "Toujours dans la mouvance de la programmation fonctionnelle permet de créer une nouvelle fonction en modifiant une existante en fixant un argument.\n", + "\n", + "Par exemple `int` prend une chaîne de caractère et une base pour retourner un entier.\n", + "On peut en créer une dédiée au binaire :" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:24.070658Z", + "start_time": "2024-10-08T19:43:24.063753Z" + } + }, + "cell_type": "code", + "source": [ + "from functools import partial\n", + "\n", + "int_bin = partial(int, base=2)\n", + "print(\"En base 10, 0101110 vaut: \", int_bin(\"0101110\"))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "En base 10, 0101110 vaut: 46\n" + ] + } + ], + "execution_count": 16 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### Exercice 4\n", + "\n", + "Modifier avec partial la fonction built-in `pow` *to the POWer of* pour qu'elle retourne toujours le résultat modulo 7." + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### Exercice 5, la conjecture de Goldbach\n", + "\n", + "En utilisant des fonctions, classiques voir `lambda`, voir des functions issues du module `functools`.\n", + "Vérifier la conjecture de Goldbach qui dit que *tout entier pair supérieur à 3 peut s'écrire comme une somme de nombres premiers* pour tous les entiers inférieurs à 1000.\n", + "Développer cela dans un script appelé `goldbach.py` ce script doit avoir une fonction chapeau qui appelle toutes les autres pour pouvoir utiliser le module `timeit` en ligne de commande et benchmarker nos développements.\n", + "\n", + "- Attention aux commentaires\n", + "- Attention aux noms de variables. \n", + "*Faites valider votre script ainsi que son exécution*. " + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "***\n", + "## Les décorateurs\n", + "\n", + "Un décorateur peut exécuter une routine avant et/ou après une fonction.\n", + "Ils peuvent utiliser les arguments passés à cette dernière." + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### Décorateurs sans arguments\n", + "\n", + "Ils peuvent utiliser une valeur déjà déclarée à l'extérieur de la fonction :" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:24.117110Z", + "start_time": "2024-10-08T19:43:24.110481Z" + } + }, + "cell_type": "code", + "source": [ + "# Décorateur sans argument inspiré de https://python.doctor/page-decorateurs-decorator-python-cours-debutants\n", + "\n", + "user = \"olivier\"\n", + "\n", + "\n", + "def mon_decorateur(fonction):\n", + " def autre_fonction():\n", + " print(\"Action refusée\")\n", + "\n", + " if user != \"olivier\":\n", + " return autre_fonction\n", + "\n", + " return fonction\n", + "\n", + "\n", + "@mon_decorateur\n", + "def do_that():\n", + " print(\"Execution des instructions\")\n", + "\n", + "\n", + "do_that()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Execution des instructions\n" + ] + } + ], + "execution_count": 17 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### Décorateur avec arguments\n", + "\n", + "Mais avec `functools` et son wrapper, ils peuvent aussi prendre ceux de la fonction décorée :" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T19:43:24.207525Z", + "start_time": "2024-10-08T19:43:24.190126Z" + } + }, + "cell_type": "code", + "source": [ + "import time\n", + "from functools import wraps\n", + "from math import sqrt\n", + "\n", + "\n", + "# Décorateur avec arguments\n", + "def timer(func):\n", + " @wraps(func)\n", + " def timeit_wrapper(*args, **kwargs):\n", + " start_time = time.perf_counter()\n", + " result = func(*args, **kwargs)\n", + " end_time = time.perf_counter()\n", + " total_time = end_time - start_time\n", + " print(f'Function {func.__name__}{args} {kwargs} Took {total_time:.4f} seconds')\n", + " return result\n", + "\n", + " return timeit_wrapper\n", + "\n", + "\n", + "@timer\n", + "def fibonacci(n):\n", + " \"\"\"\n", + " Compute the n-th Fibonacci number\n", + " \n", + " :param n: The n-th Fibonacci number to compute, type int\n", + " :return: n-th Fibonacci number \n", + " \"\"\"\n", + " if n <= 1:\n", + " return n\n", + " else:\n", + " return fibonacci(n - 1) + fibonacci(n - 2)\n", + "\n", + "\n", + "@timer\n", + "def is_prime(n):\n", + " \"\"\"\n", + " n is the number to be check whether it is prime or not\n", + " \n", + " :param n: The number to be checked, type int\n", + " :return: A boolean, True if n is prime, False otherwise\n", + " \"\"\"\n", + " prime_flag = 0\n", + "\n", + " if n > 1:\n", + " for i in range(2, int(sqrt(n)) + 1):\n", + " if n % i == 0:\n", + " prime_flag = 1\n", + " break\n", + " if prime_flag == 0:\n", + " return True\n", + " else:\n", + " return False\n", + " else:\n", + " return False\n", + "\n", + "\n", + "fibonacci(10)\n", + "\n", + "is_prime(23438545412552424235452557522453354357674555425)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(4,) {} Took 0.0002 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(5,) {} Took 0.0003 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(4,) {} Took 0.0001 seconds\n", + "Function fibonacci(6,) {} Took 0.0005 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(4,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(5,) {} Took 0.0002 seconds\n", + "Function fibonacci(7,) {} Took 0.0007 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(4,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(5,) {} Took 0.0002 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(4,) {} Took 0.0001 seconds\n", + "Function fibonacci(6,) {} Took 0.0003 seconds\n", + "Function fibonacci(8,) {} Took 0.0011 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(4,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(5,) {} Took 0.0002 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(4,) {} Took 0.0002 seconds\n", + "Function fibonacci(6,) {} Took 0.0004 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(4,) {} Took 0.0002 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(5,) {} Took 0.0003 seconds\n", + "Function fibonacci(7,) {} Took 0.0007 seconds\n", + "Function fibonacci(9,) {} Took 0.0018 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(4,) {} Took 0.0002 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(5,) {} Took 0.0003 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(4,) {} Took 0.0001 seconds\n", + "Function fibonacci(6,) {} Took 0.0005 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(4,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(5,) {} Took 0.0002 seconds\n", + "Function fibonacci(7,) {} Took 0.0007 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(4,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(5,) {} Took 0.0002 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(3,) {} Took 0.0001 seconds\n", + "Function fibonacci(1,) {} Took 0.0000 seconds\n", + "Function fibonacci(0,) {} Took 0.0000 seconds\n", + "Function fibonacci(2,) {} Took 0.0000 seconds\n", + "Function fibonacci(4,) {} Took 0.0001 seconds\n", + "Function fibonacci(6,) {} Took 0.0003 seconds\n", + "Function fibonacci(8,) {} Took 0.0010 seconds\n", + "Function fibonacci(10,) {} Took 0.0029 seconds\n", + "Function is_prime(23438545412552424235452557522453354357674555425,) {} Took 0.0000 seconds\n" + ] + }, + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 18 + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/les_conteneurs.ipynb b/6_types_iterables.ipynb similarity index 82% rename from les_conteneurs.ipynb rename to 6_types_iterables.ipynb index e3699fa..e5f06b0 100644 --- a/les_conteneurs.ipynb +++ b/6_types_iterables.ipynb @@ -13,7 +13,16 @@ { "metadata": {}, "cell_type": "markdown", - "source": "Un conteneur (*container*) est un nom générique pour définir un objet Python qui contient une collection '*un ensemble*) d'autres objets. \nLes types de conteneur sont capable de supporter: \n* Des tests d'appartenance\n* La fonction len() qui renvoie la longueur (*taille*) du conteneur \nLes types de conteneur peuvent également être:\n* Ordonné: les éléments contenus sont placés dans un ordre précis et sont donc positionnés à une place en particulier, appelé indice. \n* Indexable: Chaque élément est accessible via son indice (*position dans le conteneur*). Il est également possible de retrouver une tranche d'éléments. La plupart du temps, tous les conteneurs sont ordonnés et indexables. \n* Itérable: il est possible d'appliquer une boucle sur un conteneur (*ex: un parcours des éléments avec une boucle for*). " + "source": [ + "Un conteneur (*container*) est un nom générique pour définir un objet Python qui contient une collection, *un ensemble* d'autres objets. \n", + "Les types de conteneur sont capables de supporter : \n", + "* Des tests d'appartenance\n", + "* La fonction `len` qui renvoie la longueur (*taille*) du conteneur \n", + "Les types de conteneur peuvent également être :\n", + "* Ordonné : Les éléments contenus sont placés dans un ordre précis et sont donc positionnés à une place en particulièr, appelé indice ou *index* en anglais. \n", + "* Indexable : Chaque élément est accessible via son indice (*position dans le conteneur*). Il est également possible de retrouver une tranche d'éléments. La plupart du temps, tous les conteneurs sont ordonnés et indexables. \n", + "* Itérable : Il est possible d'appliquer une boucle sur un conteneur (*e.g., un parcours des éléments avec une boucle for*). " + ] }, { "metadata": {}, @@ -29,8 +38,8 @@ "metadata": {}, "cell_type": "markdown", "source": [ - "Une séquence est un conteneur itérable, ordonné et indexable. Les éléments présents dans une séquence possède une position précise. \n", - "On retrouve notamment quatre types de données prédéfinis: \n", + "Une séquence est un conteneur itérable, ordonné et indexable. Les éléments présents dans une séquence possèdent une position précise. \n", + "On retrouve notamment quatre types de données prédéfinis : \n", "* Les chaînes\n", "* Les listes\n", "* Les tuples\n", @@ -50,7 +59,10 @@ { "metadata": {}, "cell_type": "markdown", - "source": "Une chaîne de caractères est de type *str*. Dans une chaîne de caractères il est possible d'utiliser des séquences de caractères particulières, elles commencent par le caractère *\\\\* (*anti-slash*) et permettent d'insérer des caractères spéciaux. \nCi-dessous la liste des principaux caractères spéciaux que vous pouvez utiliser:\n" + "source": [ + "Une chaîne de caractères est de type *str*. Dans une chaîne de caractères, il est possible d'utiliser des séquences de caractères particulières, elles commencent par le caractère *\\\\* (*anti-slash*) et permettent d'insérer des caractères spéciaux. \n", + "Ci-dessous la liste des principaux caractères spéciaux que vous pouvez utiliser :\n" + ] }, { "metadata": {}, @@ -60,47 +72,76 @@ { "metadata": {}, "cell_type": "markdown", - "source": "La liste des caractères Unicode est accessible via le lien suivant: https://koor.fr/Unicode.wp" + "source": "La liste des caractères Unicode est accessible via le lien suivant : https://koor.fr/Unicode.wp" }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:50.435390Z", + "start_time": "2024-10-08T21:00:50.428188Z" + } }, "cell_type": "code", - "source": "#Exemple d'utilisation des caractères spéciaux\nprint(\"Ligne 1\\nLigne 2\\nLigne 3\")\nprint('\\u231a\\t\\u26bd')\nprint('Ajourd\\'hui')", - "execution_count": 24, + "source": [ + "# Exemple d'utilisation des caractères spéciaux\n", + "print(\"Ligne 1\\nLigne 2\\nLigne 3\")\n", + "print('\\u231a\\t\\u26bd')\n", + "print('Ajourd\\'hui')" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "Ligne 1\nLigne 2\nLigne 3\n⌚\t⚽\nAjourd'hui\n", - "name": "stdout" + "text": [ + "Ligne 1\n", + "Ligne 2\n", + "Ligne 3\n", + "⌚\t⚽\n", + "Ajourd'hui\n" + ] } - ] + ], + "execution_count": 10 }, { "metadata": {}, "cell_type": "markdown", - "source": "Deux opérations sont possibles quand on traite les chaînes de caractères: \n* *+* permet la concaténation de chaînes de caractères\n* *\\** permet de reproduire une chaîne de caractères un certain nombre de fois" + "source": [ + "Deux opérations sont possibles quand on traite les chaînes de caractères : \n", + "* `+` permet la concaténation de chaînes de caractères\n", + "* `*` permet de reproduire une chaîne de caractères un certain nombre de fois" + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:51.060128Z", + "start_time": "2024-10-08T21:00:51.052554Z" + } }, "cell_type": "code", - "source": "#Exemple d'une concaténation de chaînes de caractères\nniveau = \"Bachelor \"\netablissement = \"Saint Michel\"\nprint(niveau + etablissement)\n#Exemple d'une répétition d'une chaîne de caractères\ncours = \"Python\"\nprint(cours * 3)", - "execution_count": 27, + "source": [ + "# Exemple d'une concaténation de chaînes de caractères\n", + "love = \"I love \"\n", + "who = \"Digicomp Academy\"\n", + "print(love + who)\n", + "# Exemple d'une répétition d'une chaîne de caractères\n", + "cours = \"Python\"\n", + "print(cours * 3)" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "Bachelor Saint Michel\nPythonPythonPython\n", - "name": "stdout" + "text": [ + "I love Digicomp Academy\n", + "PythonPythonPython\n" + ] } - ] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "***L'opérateur *+* permet de concaténer, c'est-à-dire d'assembler des chaînes de caractères. \nL'opérateur *\\** permet de dupliquer, c'est-à-dire de répéter une chaîne de caractères un certain nombre de fois.***" + ], + "execution_count": 11 }, { "metadata": {}, @@ -109,21 +150,32 @@ }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:51.144589Z", + "start_time": "2024-10-08T21:00:51.106302Z" + } }, "cell_type": "code", - "source": "#Exemple d'opération interdite\nniveau = \"Bachelor\"\nprint(niveau * niveau)", - "execution_count": 28, + "source": [ + "# Exemple d'opération interdite\n", + "who = \"Digicomp Academy\"\n", + "print(who * who)" + ], "outputs": [ { - "output_type": "stream", - "text": "Traceback (most recent call last):\n File \"\", line 3, in \nTypeError: can't multiply sequence by non-int of type 'str'\n", - "name": "stderr" - }, - { - "output_type": "error" + "ename": "TypeError", + "evalue": "can't multiply sequence by non-int of type 'str'", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mTypeError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[12], line 3\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[38;5;66;03m# Exemple d'opération interdite\u001B[39;00m\n\u001B[1;32m 2\u001B[0m who \u001B[38;5;241m=\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mDigicomp Academy\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m----> 3\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[43mwho\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43m \u001B[49m\u001B[43mwho\u001B[49m)\n", + "\u001B[0;31mTypeError\u001B[0m: can't multiply sequence by non-int of type 'str'" + ] } - ] + ], + "execution_count": 12 }, { "metadata": {}, @@ -133,42 +185,81 @@ { "metadata": {}, "cell_type": "markdown", - "source": "Une liste est une collection de données ordonnées et modifiables. \nLes éléments qui composent une liste sont séparés par des *,* et l'ensemble est délimité par des crochets *[]*. Tous les éléments peuvent être hétérogènes ou non, c'est-à-dire de même type ou non. " + "source": [ + "Une liste est une collection de données ordonnées et modifiables. \n", + "Les éléments qui composent une liste sont séparés par des `,` et l'ensemble est délimité par des crochets `[]`. Tous les éléments peuvent être hétérogènes ou non, c’est-à-dire de même type ou non. " + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:51.359101Z", + "start_time": "2024-10-08T21:00:51.352336Z" + } }, "cell_type": "code", - "source": "#Exemple de création de listes\nliste_formes = [\"Triangle\", \"Cercle\", \"Quadrilatère\"]\nma_liste = [\"Bonjour\", False, 0, 1, 3.14159]\nprint(liste_formes)\nprint(ma_liste)\nprint(liste_formes + ma_liste)", - "execution_count": 1, + "source": [ + "# Exemple de création de listes\n", + "liste_formes = [\"Triangle\", \"Cercle\", \"Quadrilatère\"]\n", + "ma_liste = [\"Bonjour\", False, 0, 1, 3.14159]\n", + "print(liste_formes)\n", + "print(ma_liste)\n", + "print(liste_formes + ma_liste)" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "['Triangle', 'Cercle', 'Quadrilatère']\n['Bonjour', False, 0, 1, 3.14159]\n['Triangle', 'Cercle', 'Quadrilatère', 'Bonjour', False, 0, 1, 3.14159]\n", - "name": "stdout" + "text": [ + "['Triangle', 'Cercle', 'Quadrilatère']\n", + "['Bonjour', False, 0, 1, 3.14159]\n", + "['Triangle', 'Cercle', 'Quadrilatère', 'Bonjour', False, 0, 1, 3.14159]\n" + ] } - ] + ], + "execution_count": 13 }, { "metadata": {}, "cell_type": "markdown", - "source": "Les éléments dans une liste sont accessibles via leur indice c'est-à-dire la place qu'ils occupent dans la liste. \nLe premier élément est placé à l'indice **0**. Les éléments suivants voient leur indice incrémenté de 1 à chaque fois. \nIl est possible de parcourir les éléments d'une liste par ordre décroissant c'est-à-dire les éléments situés à la fin, en plaçant une valeur négative comme indice de la liste (*exemple: -1 correspond au premier élément en partant de la fin de la liste*). " + "source": [ + "Les éléments dans une liste sont accessibles via leur indice, c’est-à-dire la place qu'ils occupent dans la liste. \n", + "Le premier élément est placé à l'indice `0`. Les éléments suivants voient leur indice incrémenté de 1 à chaque fois. \n", + "Il est possible de parcourir les éléments d'une liste par ordre décroissant, c’est-à-dire les éléments situés à la fin, en plaçant une valeur négative comme indice de la liste (*exemple: -1 correspond au premier élément en partant de la fin de la liste*). " + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:51.815162Z", + "start_time": "2024-10-08T21:00:51.807883Z" + } }, "cell_type": "code", - "source": "#Exemple d'accès aux éléments d'une liste par leur indice (croissant)\ncouleurs = [\"Rouge\", \"Orange\", \"Noir\", \"Marron\", \"Bleu\", \"Violet\", \"Jaune\"]\nprint(couleurs[0])\nprint(couleurs[4])\n#Exemple d'accès aux éléments d'une lisye par leur indice (décroissant)\nprint(couleurs[-1])\nprint(couleurs[-3])", - "execution_count": 6, + "source": [ + "# Exemple d'accès aux éléments d'une liste par leur indice (croissant)\n", + "couleurs = [\"Rouge\", \"Orange\", \"Noir\", \"Marron\", \"Bleu\", \"Violet\", \"Jaune\"]\n", + "print(couleurs[0])\n", + "print(couleurs[4])\n", + "#Exemple d'accès aux éléments d'une liste par leur indice (décroissant)\n", + "print(couleurs[-1])\n", + "print(couleurs[-3])" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "Rouge\nBleu\nJaune\nBleu\n", - "name": "stdout" + "text": [ + "Rouge\n", + "Bleu\n", + "Jaune\n", + "Bleu\n" + ] } - ] + ], + "execution_count": 14 }, { "metadata": {}, @@ -178,22 +269,41 @@ { "metadata": {}, "cell_type": "markdown", - "source": "Il est également possible de créer des listes en itérant une suite de nombres grâce à la fonction *range()*. Cette fonction génère des suites arithmétiques. " + "source": "Il est également possible de créer des listes en itérant une suite de nombres grâce à la fonction `range`. Cette fonction génère des suites arithmétiques. " }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:51.962818Z", + "start_time": "2024-10-08T21:00:51.955514Z" + } }, "cell_type": "code", - "source": "#Exemple d'initialisation de listes avec l'itérateur d'entiers range()\nma_liste = list(range(10))\nprint(ma_liste)\nma_liste2 = list(range(5, 10))\nprint(ma_liste2)\nliste_impair = list(range(1, 10, 2))\nprint(liste_impair)\nliste_pair = list(range(0, 10, 2))\nprint(liste_pair)", - "execution_count": 3, + "source": [ + "# Exemple d'initialisation de listes avec l'itérateur d'entiers range()\n", + "ma_liste = list(range(10))\n", + "print(ma_liste)\n", + "ma_liste2 = list(range(5, 10))\n", + "print(ma_liste2)\n", + "liste_impair = list(range(1, 10, 2))\n", + "print(liste_impair)\n", + "liste_pair = list(range(0, 10, 2))\n", + "print(liste_pair)" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n[5, 6, 7, 8, 9]\n[1, 3, 5, 7, 9]\n[0, 2, 4, 6, 8]\n", - "name": "stdout" + "text": [ + "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", + "[5, 6, 7, 8, 9]\n", + "[1, 3, 5, 7, 9]\n", + "[0, 2, 4, 6, 8]\n" + ] } - ] + ], + "execution_count": 15 }, { "metadata": {}, @@ -231,27 +341,44 @@ "trusted": true }, "cell_type": "markdown", - "source": "Il est possible de supprimer, remplacer ou insérer un ou plusieurs éléments dans une liste, en ce sens il faut indiquer un intervalle ou tranche de valeurs par l'intermédiaire de la commande *range()*. \n" + "source": "Il est possible de supprimer, remplacer ou insérer un ou plusieurs éléments dans une liste, il faut indiquer un interval ou tranche de valeurs à modifier. \n" }, { "metadata": {}, "cell_type": "markdown", - "source": "Pour spécifier une tranche de valeurs il faut insérer le caractère *:* en précisant la valeur de départ (indice de début) suivie de la valeur finale (indice de fin), cette dernière étant exclue. " + "source": "Pour spécifier une tranche de valeurs il faut insérer le caractère `:` en précisant la valeur de départ (indice de début) suivie de la valeur finale (indice de fin), cette dernière étant exclue. " }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:52.117395Z", + "start_time": "2024-10-08T21:00:52.111199Z" + } }, "cell_type": "code", - "source": "#Exemple de manipulation des tranches de listes\ncouleurs = [\"Rouge\", \"Orange\", \"Noir\", \"Marron\", \"Bleu\", \"Violet\", \"Jaune\"]\n#Parcours dans un intervalle au milieu de la liste\nprint(couleurs[2:6])\n#Parcours dans un intervalle depuis un certain indice jusqu'à la fin\nprint(couleurs[2:])\n#Parcours dans un intervalle depuis le début jusqu'à un certain indice exclu\nprint(couleurs[:4])", - "execution_count": 5, + "source": [ + "# Exemple de manipulation des tranches de listes\n", + "couleurs = [\"Rouge\", \"Orange\", \"Noir\", \"Marron\", \"Bleu\", \"Violet\", \"Jaune\"]\n", + "# Parcours dans un intervalle au milieu de la liste\n", + "print(couleurs[2:6])\n", + "# Parcours dans un intervalle depuis un certain indice jusqu'à la fin\n", + "print(couleurs[2:])\n", + "# Parcours dans un intervalle depuis le début jusqu'à un certain indice exclu\n", + "print(couleurs[:4])" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "['Noir', 'Marron', 'Bleu', 'Violet']\n['Noir', 'Marron', 'Bleu', 'Violet', 'Jaune']\n['Rouge', 'Orange', 'Noir', 'Marron']\n", - "name": "stdout" + "text": [ + "['Noir', 'Marron', 'Bleu', 'Violet']\n", + "['Noir', 'Marron', 'Bleu', 'Violet', 'Jaune']\n", + "['Rouge', 'Orange', 'Noir', 'Marron']\n" + ] } - ] + ], + "execution_count": 16 }, { "metadata": {}, @@ -260,23 +387,39 @@ }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:52.170115Z", + "start_time": "2024-10-08T21:00:52.163948Z" + } }, "cell_type": "code", - "source": "#Exemple d'une copie de liste\ncouleurs = [\"Noir\", \"Marron\", \"Rouge\", \"Orange\"]\ncolors = couleurs\nprint(\"Liste copie: \", colors)\ncolors[0] = \"Blanc\"\nprint(\"Liste copie modifiée: \", colors)\nprint(\"Liste souche: \", couleurs)", - "execution_count": 9, + "source": [ + "# Exemple d'une copie de liste\n", + "couleurs = [\"Noir\", \"Marron\", \"Rouge\", \"Orange\"]\n", + "colors = couleurs\n", + "print(\"Liste copie: \", colors)\n", + "colors[0] = \"Blanc\"\n", + "print(\"Liste copie modifiée: \", colors)\n", + "print(\"Liste souche: \", couleurs)" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "Liste copie: ['Noir', 'Marron', 'Rouge', 'Orange']\nListe copie modifiée: ['Blanc', 'Marron', 'Rouge', 'Orange']\nListe souche: ['Blanc', 'Marron', 'Rouge', 'Orange']\n", - "name": "stdout" + "text": [ + "Liste copie: ['Noir', 'Marron', 'Rouge', 'Orange']\n", + "Liste copie modifiée: ['Blanc', 'Marron', 'Rouge', 'Orange']\n", + "Liste souche: ['Blanc', 'Marron', 'Rouge', 'Orange']\n" + ] } - ] + ], + "execution_count": 17 }, { "metadata": {}, "cell_type": "markdown", - "source": "On constate donc que les deux listes ont été modifées. " + "source": "On constate donc que les deux listes ont été modifiées. " }, { "metadata": {}, @@ -285,18 +428,34 @@ }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:52.303520Z", + "start_time": "2024-10-08T21:00:52.297524Z" + } }, "cell_type": "code", - "source": "#Exemple d'une copie de liste indépendante\ncouleurs = [\"Noir\", \"Marron\", \"Rouge\", \"Orange\"]\ncolors = couleurs[:]\nprint(\"Liste copie: \", colors)\ncolors[0] = \"Blanc\"\nprint(\"Liste copie modifiée: \", colors)\nprint(\"Liste souche: \", couleurs)", - "execution_count": 10, + "source": [ + "# Exemple d'une copie de liste indépendante\n", + "couleurs = [\"Noir\", \"Marron\", \"Rouge\", \"Orange\"]\n", + "colors = couleurs[:]\n", + "print(\"Liste copie: \", colors)\n", + "colors[0] = \"Blanc\"\n", + "print(\"Liste copie modifiée: \", colors)\n", + "print(\"Liste souche: \", couleurs)" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "Liste copie: ['Noir', 'Marron', 'Rouge', 'Orange']\nListe copie modifiée: ['Blanc', 'Marron', 'Rouge', 'Orange']\nListe souche: ['Noir', 'Marron', 'Rouge', 'Orange']\n", - "name": "stdout" + "text": [ + "Liste copie: ['Noir', 'Marron', 'Rouge', 'Orange']\n", + "Liste copie modifiée: ['Blanc', 'Marron', 'Rouge', 'Orange']\n", + "Liste souche: ['Noir', 'Marron', 'Rouge', 'Orange']\n" + ] } - ] + ], + "execution_count": 18 }, { "metadata": {}, @@ -331,21 +490,35 @@ { "metadata": {}, "cell_type": "markdown", - "source": "Écrire un script Python qui permet de jouer au jeu du Pendu. \n* Le joueur 1 entre un mot dans le programme. Les caractères qui composent le mot apparaitront sous forme de *_* pour le joueur. Si vous souhaitez que le mot saisi n'apparaisse par à l'écran vous pouvez utiliser la méthode *getpass()* contenue dans le module *getpass* - Voir exemple ci-dessous. \n* Le joueur 2, propose une lettre\n* L'ordinateur indique alors si la lettre est présente ou non dans le mot. Si la lettre est présente dans le mot, elle est alors positionnée et affichée en lieu et place du ou des *_*. \n* BONUS: Dessiner au fur et à mesure des erreurs, le personnage du pendu. \n\n- Attention aux commentaires\n- Attention aux noms de variables. \n*Faites valider votre script ainsi que son exécution.*\n" + "source": [ + "Écrire un script Python qui permet de jouer au jeu du Pendu. \n", + "* Le joueur 1 entre un mot dans le programme. Les caractères qui composent le mot apparaitront sous forme de `_` pour le joueur. Si vous souhaitez que le mot saisi n'apparaisse pas à l'écran vous pouvez utiliser la méthode `getpass()` contenue dans le module `getpass` - Voir exemple ci-dessous. \n", + "* Le joueur 2, propose une lettre\n", + "* L'ordinateur indique alors si la lettre est présente ou non dans le mot. Si la lettre est présente dans le mot, elle est alors positionnée et affichée en lieu et place du ou des *_*. \n", + "* BONUS: Dessiner au fur et à mesure des erreurs, le personnage du pendu. \n", + "\n", + "- Attention aux commentaires\n", + "- Attention aux noms de variables. \n", + "*Faites valider votre script ainsi que son exécution.*\n" + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:55.419579Z", + "start_time": "2024-10-08T21:00:52.451194Z" + } }, "cell_type": "code", "source": [ - "#Exemple de saisie cachée\n", + "# Exemple de saisie cachée\n", "from getpass import getpass\n", "\n", "mot = getpass(\"Veuillez saisir le mot secret: \")" ], - "execution_count": null, - "outputs": [] + "outputs": [], + "execution_count": 19 }, { "metadata": {}, @@ -355,7 +528,16 @@ { "metadata": {}, "cell_type": "markdown", - "source": "**€€€ La monnaie SVP €€€** \nUn distributeur de banque dispose de billets de 10, 20, 50, 100, 200 et 500€. On suppose que la banque ne connaît pas la crise et possède donc un nombre illimité de billets). \nÉcrire un script Python qui demande la somme désirée par l'utilisateur et propose une répartition en proposant le moins de billets possibles. Dans le cas où la banque ne peut pas donner l'intégralité de la somme souhaitée, elle distribue le montant possible et spécifie à l'utilisateur le montant manquant. \n*Exemple: 57€ demandé = 50€ x 1. Les 7€ manquants ne peuvent pas être distribués.* \n\n- Attention aux commentaires\n- Attention aux noms de variables. \n*Faites valider votre script ainsi que son exécution.*" + "source": [ + "**€€€ La monnaie SVP €€€** \n", + "Un distributeur de banque dispose de billets de 10, 20, 50, 100, 200 et 500 €. On suppose que la banque ne connaît pas la crise et possède donc un nombre illimité de billets. \n", + "Écrire un script Python qui demande la somme désirée par l'utilisateur et propose une répartition en proposant le moins de billets possible. Dans le cas où la banque ne peut pas donner l'intégralité de la somme souhaitée, elle distribue le montant possible et spécifie à l'utilisateur le montant manquant. \n", + "* Exemple : 57€ demandé = 50 € x 1. Les 7 € manquants ne peuvent pas être distribués.* \n", + "\n", + "- Attention aux commentaires\n", + "- Attention aux noms de variables. \n", + "*Faites valider votre script ainsi que son exécution.*" + ] }, { "metadata": {}, @@ -365,7 +547,17 @@ { "metadata": {}, "cell_type": "markdown", - "source": "**Blackjack** \nLe blackjack est un jeu opposant un joueur à la banque, le but est de se rapprocher de 21 sans dépasser ce total. Les valeurs des 13 cartes seront représentées dans une liste (Tête = 10 points, As = 1 ou 11 points). Le banquier et le joueur choisissent chacun leur tour le nombre de cartes à tirer. Si l'un des deux dépasse 21, il perd la partie. Si il y a égalité, c'est le joueur ayant le moins de cartes qui gagne. Le joueur avec le score le plus proche ou égale à 21 remporte la partie. Si les deux joueurs dépassent 21, la partie est nulle. La saisie du 0 permet d'arrêter la partie. La banque continue de tirer des cartes tant que son score n'est pas au moins égale à 17. A vous de définir la stratégie de jeu de l'ordinateur, c'est-à-dire le nombre de cartes à tirer ou non en fonction de la valeur acquise. \n\n- Attention aux commentaires\n- Attention aux noms de variables. \n*Faites valider votre script ainsi que son exécution.*\n***" + "source": [ + "**Blackjack** \n", + "Le blackjack est un jeu opposant un joueur à la banque, le but est de se rapprocher de 21 sans dépasser ce total. Les valeurs des 13 cartes seront représentées dans une liste (Figure = 10 points, As = 11 ou 1 points si le total dépasse 21). Le banquier et le joueur choisissent chacun à leur tour le nombre de cartes à tirer. Si l'un des deux dépasse 21, il perd la partie. S'il y a égalité, c'est le joueur ayant le moins de cartes qui gagne. Le joueur avec le score le plus proche ou égale à 21 remporte la partie. Si les deux joueurs dépassent 21, la partie est nulle. La saisie du 0 permet d'arrêter la partie. La banque continue de tirer des cartes tant que son score n’est pas au moins égale à 17. À vous de définir la stratégie de jeu de l'ordinateur, c’est-à-dire le nombre de cartes à tirer ou non en fonction de la valeur acquise\n", + "\n", + "Voir https://www.casinosbarriere.com/fr/nos-jeux/jeux-de-table/blackjack.html.\n", + "\n", + "- Attention aux commentaires\n", + "- Attention aux noms de variables. \n", + "*Faites valider votre script ainsi que son exécution.*\n", + "***" + ] }, { "metadata": {}, @@ -375,65 +567,112 @@ { "metadata": {}, "cell_type": "markdown", - "source": "Un tuple est similaire à une liste, c'est-à-dire une collection d'objets. \nPour créer un tuple il faut utiliser les caractères *()* au lieu des *[]* pour une liste. Tout comme pour une liste, les éléments sont séparés par des *,*. " + "source": [ + "Un tuple est similaire à une liste, c’est-à-dire une collection d'objets. \n", + "Pour créer un tuple, il faut utiliser les caractères `()` au lieu des `[]` pour une liste. Tout comme pour une liste, les éléments sont séparés par des `,`. " + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:55.430952Z", + "start_time": "2024-10-08T21:00:55.423262Z" + } }, "cell_type": "code", - "source": "#Exemple de création d'un tuple et d'une liste\ncouleurs_tuple = (\"Noir\", \"Marron\", \"Rouge\", \"Orange\")\nprint(type(couleurs_tuple))\ncouleurs_liste = [\"Noir\", \"Marron\", \"Rouge\", \"Orange\"]\nprint(type(couleurs_liste))", - "execution_count": 31, + "source": [ + "# Exemple de création d'un tuple et d'une liste\n", + "couleurs_tuple = (\"Noir\", \"Marron\", \"Rouge\", \"Orange\")\n", + "print(type(couleurs_tuple))\n", + "couleurs_liste = [\"Noir\", \"Marron\", \"Rouge\", \"Orange\"]\n", + "print(type(couleurs_liste))" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "\n\n", - "name": "stdout" + "text": [ + "\n", + "\n" + ] } - ] + ], + "execution_count": 20 }, { "metadata": {}, "cell_type": "markdown", - "source": "Pour accéder aux élémens d'un tuple, il faut procéder de la même manière qu'avec une liste. Chaque élément a une place précise, appelée indice. La fonction *len()* est également utilisable et renvoie la longueur du tuple, c'est-à-dire le nombre d'éléments qui le compose. " + "source": "Pour accéder aux éléments d'un tuple, il faut procéder de la même manière qu'avec une liste. Chaque élément à une place précise, appelée indice. La fonction `len()` est également utilisable et renvoie la longueur du tuple, c'est-à-dire le nombre d'éléments qui le compose. " }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:55.442654Z", + "start_time": "2024-10-08T21:00:55.434036Z" + } }, "cell_type": "code", - "source": "#Exemple de manipulation des éléments d'un tuple\ncouleurs_tuple = (\"Noir\", \"Marron\", \"Rouge\", \"Orange\")\nprint(len(couleurs_tuple))\nprint(couleurs_tuple[0])\nprint(couleurs_tuple[:3])\nprint(couleurs_tuple[2:])", - "execution_count": 34, + "source": [ + "# Exemple de manipulation des éléments d'un tuple\n", + "couleurs_tuple = (\"Noir\", \"Marron\", \"Rouge\", \"Orange\")\n", + "print(len(couleurs_tuple))\n", + "print(couleurs_tuple[0])\n", + "print(couleurs_tuple[:3])\n", + "print(couleurs_tuple[2:])" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "4\nNoir\n('Noir', 'Marron', 'Rouge')\n('Rouge', 'Orange')\n", - "name": "stdout" + "text": [ + "4\n", + "Noir\n", + "('Noir', 'Marron', 'Rouge')\n", + "('Rouge', 'Orange')\n" + ] } - ] + ], + "execution_count": 21 }, { "metadata": {}, "cell_type": "markdown", - "source": "**Quelle est alors la différence entre une liste et un tuple?** \nUn tuple ne peut pas être modifié, en effet on ne peut ni modifier les éléments qui le composent, ni ajouter ou supprimer des éléments !" + "source": [ + "**Quelle est alors la différence entre une liste et un tuple ?** \n", + "Un tuple ne peut pas être modifié, en effet, on ne peut ni modifier les éléments qui le composent, ni ajouter ou supprimer des éléments !" + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:55.489141Z", + "start_time": "2024-10-08T21:00:55.463500Z" + } }, "cell_type": "code", - "source": "#Exemple modification d'un tuple\ncouleurs_tuple = (\"Noir\", \"Marron\", \"Rouge\", \"Orange\")\ncouleurs_tuple[0] = \"Blanc\"\nprint(couleurs_tuple)", - "execution_count": 33, + "source": [ + "# Exemple modification d'un tuple\n", + "couleurs_tuple = (\"Noir\", \"Marron\", \"Rouge\", \"Orange\")\n", + "couleurs_tuple[0] = \"Blanc\"\n", + "print(couleurs_tuple)" + ], "outputs": [ { - "output_type": "stream", - "text": "Traceback (most recent call last):\n File \"\", line 3, in \nTypeError: 'tuple' object does not support item assignment\n", - "name": "stderr" - }, - { - "output_type": "error" + "ename": "TypeError", + "evalue": "'tuple' object does not support item assignment", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mTypeError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[22], line 3\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[38;5;66;03m# Exemple modification d'un tuple\u001B[39;00m\n\u001B[1;32m 2\u001B[0m couleurs_tuple \u001B[38;5;241m=\u001B[39m (\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mNoir\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mMarron\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mRouge\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mOrange\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[0;32m----> 3\u001B[0m \u001B[43mcouleurs_tuple\u001B[49m\u001B[43m[\u001B[49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m]\u001B[49m \u001B[38;5;241m=\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mBlanc\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[1;32m 4\u001B[0m \u001B[38;5;28mprint\u001B[39m(couleurs_tuple)\n", + "\u001B[0;31mTypeError\u001B[0m: 'tuple' object does not support item assignment" + ] } - ] + ], + "execution_count": 22 }, { "metadata": {}, @@ -447,88 +686,192 @@ }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:55.552062Z", + "start_time": "2024-10-08T21:00:55.546101Z" + } }, "cell_type": "code", - "source": "#Exemple d'objets immuables\nnote_info = 9\nmoyenne_info = note_info\nnote_info = 16\nprint(note_info)\nprint(moyenne_info)\n", - "execution_count": 35, + "source": [ + "# Exemple d'objets immuables\n", + "note_info = 9\n", + "moyenne_info = note_info\n", + "note_info = 16\n", + "print(note_info)\n", + "print(moyenne_info)" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "16\n9\n", - "name": "stdout" + "text": [ + "16\n", + "9\n" + ] + } + ], + "execution_count": 23 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "Les tuples sont immuables, c'est-à-dire qu'ils ne peuvent pas être modifiés :" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-08T21:00:55.630095Z", + "start_time": "2024-10-08T21:00:55.608194Z" } + }, + "cell_type": "code", + "source": [ + "inchangeable = (1, 2, 3)\n", + "inchangeable[0] = 4" + ], + "outputs": [ + { + "ename": "TypeError", + "evalue": "'tuple' object does not support item assignment", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mTypeError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[24], line 2\u001B[0m\n\u001B[1;32m 1\u001B[0m inchageable \u001B[38;5;241m=\u001B[39m (\u001B[38;5;241m1\u001B[39m, \u001B[38;5;241m2\u001B[39m, \u001B[38;5;241m3\u001B[39m)\n\u001B[0;32m----> 2\u001B[0m \u001B[43minchageable\u001B[49m\u001B[43m[\u001B[49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m]\u001B[49m \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m4\u001B[39m\n", + "\u001B[0;31mTypeError\u001B[0m: 'tuple' object does not support item assignment" + ] + } + ], + "execution_count": 24 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### Les vertus de l'immutabilité\n", + "\n", + "En design logiciel les objets immuables sont souvent considérés comme plus safe.\n", + "En effet leur immutabilité permet entre autre d'éviter des effets de bord, des modifications involontaires, des bugs difficiles à débugger." ] }, { "metadata": {}, "cell_type": "markdown", - "source": "Dans l'exemple ci-dessus on constate que la variable *note_info* a été modifiée mais que la variable *moyenne_info* elle ne l'a pas été. " + "source": "Dans l'exemple ci-dessus on constate que la variable `note_info` a été modifiée mais que la variable *moyenne_info* elle ne l'a pas été. " }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:55.770729Z", + "start_time": "2024-10-08T21:00:55.764559Z" + } }, "cell_type": "code", - "source": "#Exemple d'objets mutables\nnote_info1 = [19, 14, 10, 18]\nnote_info2 = note_info1\nnote_info1[0] = 9\nprint(note_info1)\nprint(note_info2)", - "execution_count": 36, + "source": [ + "# Exemple d'objets mutables\n", + "note_info1 = [19, 14, 10, 18]\n", + "note_info2 = note_info1\n", + "note_info1[0] = 9\n", + "print(note_info1)\n", + "print(note_info2)" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "[9, 14, 10, 18]\n[9, 14, 10, 18]\n", - "name": "stdout" + "text": [ + "[9, 14, 10, 18]\n", + "[9, 14, 10, 18]\n" + ] } - ] + ], + "execution_count": 25 }, { "metadata": {}, "cell_type": "markdown", - "source": "Dans l'exemple ci-dessus on constate que la variable *note_info1* a été modifiée et que la variable *note_info2* également. " + "source": "Dans l'exemple ci-dessus on constate que la variable `note_info1` a été modifiée et que la variable `note_info2` également. " }, { "metadata": {}, "cell_type": "markdown", - "source": "L'utilisation de la fonction *id()* qui renvoie l'identité de l'objet passé en paramètre. Il s'agit d'un nombre entier garanti unique et constant pour le dit objet durant sa durée de vie. \n*Pour simplifier les choses cela peut être assimilé à l'adresse de l'objet en mémoire.* " + "source": [ + "L'utilisation de la fonction `id()` qui renvoie l'identité de l'objet passé en paramètre. Il s'agit d'un nombre entier garanti unique et constant pour le dit objet durant sa durée de vie. \n", + "*Pour simplifier les choses cela peut être assimilé à l'adresse de l'objet en mémoire.* " + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:55.944961Z", + "start_time": "2024-10-08T21:00:55.939213Z" + } }, "cell_type": "code", - "source": "#Exemple d'objets immuables\nnote_info = 9\nmoyenne_info = note_info\nprint(id(note_info), id(moyenne_info))\nnote_info = 16\nprint(id(note_info), id(moyenne_info))", - "execution_count": 38, + "source": [ + "# Exemple d'objets immuables\n", + "note_info = 9\n", + "moyenne_info = note_info\n", + "print(id(note_info), id(moyenne_info))\n", + "note_info = 16\n", + "print(id(note_info), id(moyenne_info))" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "2810228 2810228\n2810340 2810228\n", - "name": "stdout" + "text": [ + "11754152 11754152\n", + "11754376 11754152\n" + ] } - ] + ], + "execution_count": 26 }, { "metadata": {}, "cell_type": "markdown", - "source": "On constate donc qu'au moment de l'initialisation des deux variables, celles-ci pointent vers le même emplacement mémoire *(=2810228)*. \nAprès modification d'une des deux variables, celle-ci pointe alors vers un nouvel emplacement mémoire *(=2810340)* tantis que l'autre pointe toujours sur le même emplacement mémoire *(=2810228)*. " + "source": [ + "On constate donc qu'au moment de l'initialisation des deux variables, celles-ci pointent vers le même emplacement mémoire. \n", + "Après modification d'une des deux variables, celle-ci pointe alors vers un nouvel emplacement mémoire tandis que l'autre pointe toujours sur le même emplacement mémoire. " + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:56.032103Z", + "start_time": "2024-10-08T21:00:56.026101Z" + } }, "cell_type": "code", - "source": "#Exemple d'objets mutables\nnote_info1 = [19, 14, 10, 18]\nnote_info2 = note_info1\nprint(id(note_info1), id(note_info2))\nnote_info1[0] = 9\nprint(id(note_info1), id(note_info2))", - "execution_count": 39, + "source": [ + "# Exemple d'objets mutables\n", + "note_info1 = [19, 14, 10, 18]\n", + "note_info2 = note_info1\n", + "print(id(note_info1), id(note_info2))\n", + "note_info1[0] = 9\n", + "print(id(note_info1), id(note_info2))" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "20620688 20620688\n20620688 20620688\n", - "name": "stdout" + "text": [ + "137178168204352 137178168204352\n", + "137178168204352 137178168204352\n" + ] } - ] + ], + "execution_count": 27 }, { "metadata": {}, "cell_type": "markdown", - "source": "Avec des objets mutables Les variables pointent toujours vers les mêmes emplacements mémoire avant ou après modification *(=20620688)*. " + "source": "Avec des objets mutables Les variables pointent toujours vers les mêmes emplacements mémoire avant ou après modification. " }, { "metadata": {}, @@ -543,72 +886,130 @@ { "metadata": {}, "cell_type": "markdown", - "source": "Les dictionnaires sont des tableaux associatifs, c'est-à-dire qu'ils associent une clé à une valeur. Un tableau associatif, dictionnaire, est un **type de données** (*dict*) permettant de stocker des couples (*cle: valeur*). Les dictionnaires sont des collections non ordonnées d'objets. Il ne s'agit pas d'objets séquentiels comme peuvent l'être les listes, les tuples ou même les chaînes de caractères. L'accès aux valeurs est très rapide par l'intermédiaire des clés. **Les clés dans un dictionnaire étant uniques et immuables !**. \n" + "source": "Les dictionnaires sont des tableaux associatifs, c'est-à-dire qu'ils associent une clé à une valeur. Un tableau associatif, dictionnaire, est un **type de données** (*dict*) permettant de stocker des couples (*clé: valeur*). Les dictionnaires sont des collections non ordonnées d'objets. Il ne s'agit pas d'objets séquentiels comme peuvent l'être les listes, les tuples ou même les chaînes de caractères. L'accès aux valeurs est très rapide par l'intermédiaire des clés. **Les clés dans un dictionnaire étant uniques et immuables !**. \n" }, { "metadata": {}, "cell_type": "markdown", - "source": "Pour créer un dictionnaire il faut utiliser les caractères *{}*. Lors de l'initialisation il est possible de créer un dictionnaire vide ou de créer un dictionnaire avec les couples désirés. Pour insérer des couples lors de l'initialisation il est nécessaire de séparer avec le caractère *:* la clé de la valeurs associée. \nLes couples sont séparés entre eux par des *,* comme dans les listes, tuples, ... " + "source": [ + "Pour créer un dictionnaire, il faut utiliser les caractères *{}*. Lors de l'initialisation il est possible de créer un dictionnaire vide ou de créer un dictionnaire avec les couples désirés. Pour insérer des couples lors de l'initialisation il est nécessaire de séparer avec le caractère *:* la clé de la valeur associée. \n", + "Les couples sont séparés entre eux par des `,` comme dans les listes, tuples, ... " + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:56.156394Z", + "start_time": "2024-10-08T21:00:56.149810Z" + } }, "cell_type": "code", - "source": "#Exemple de création de dictionnaires\ncouleurs_dico = {}\nprint(type(couleurs_dico))\ncouleurs_dico[\"Noir\"] = 0\ncouleurs_dico[\"Marron\"] = 1\nprint(couleurs_dico)\nnotes_dico = {\"Info\": 16, \"Communication\": 13, \"Anglais\": 20}\nprint(notes_dico)", - "execution_count": 41, + "source": [ + "# Exemple de création de dictionnaires\n", + "couleurs_dico = {}\n", + "print(type(couleurs_dico))\n", + "couleurs_dico[\"Noir\"] = 0\n", + "couleurs_dico[\"Marron\"] = 1\n", + "print(couleurs_dico)\n", + "notes_dico = {\"Info\": 16, \"Communication\": 13, \"Anglais\": 20}\n", + "print(notes_dico)" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "\n{'Noir': 0, 'Marron': 1}\n{'Info': 16, 'Communication': 13, 'Anglais': 20}\n", - "name": "stdout" + "text": [ + "\n", + "{'Noir': 0, 'Marron': 1}\n", + "{'Info': 16, 'Communication': 13, 'Anglais': 20}\n" + ] } - ] + ], + "execution_count": 28 }, { "metadata": {}, "cell_type": "markdown", - "source": "Comme présenté dans l'exemple ci-dessus, pour ajouter des couples dans le dictionnaire, il faut préciser la clé entre *[]* puis affecter une valeur, cette méthode peut se rapprocher de la manière de procéder avec une liste ou un tuple où l'indice est précisé dans les crochets, tandis que pour les dictionnaires c'est le clé qui est spécifiée. \nSi lors de l'ajour d'un élément dans un dictionnaire, si la clé est déjà existante il n'y aura alors pas d'insertion de nouvelle valeur, mais un remplacement. " + "source": [ + "Comme présenté dans l'exemple ci-dessus, pour ajouter des couples dans le dictionnaire, il faut préciser la clé entre *[]* puis affecter une valeur, cette méthode peut se rapprocher de la manière de procéder avec une liste ou un tuple où l'indice est précisé entre crochets, tandis que pour les dictionnaires c'est le clé qui est spécifiée.\n", + "Si lors de l'ajout d'un élément dans un dictionnaire, la clé est déjà existante il n'y aura alors pas d'insertion de nouvelle valeur, mais un remplacement. " + ] }, { "metadata": {}, "cell_type": "markdown", - "source": "Pour accéder à la valeur associée à une clé, il est nécessaire de spécifier la clé entre *[]*. Pour connaître l'ensemble des couples clés/valeurs, il est possible d'itérer sur un dictionnaire avec une boucle *for*. " + "source": "Pour accéder à la valeur associée à une clé, il est nécessaire de spécifier la clé entre `[]`. Pour connaître l'ensemble des couples clés/valeurs, il est possible d'itérer sur un dictionnaire avec une boucle `for`. " }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:56.279070Z", + "start_time": "2024-10-08T21:00:56.272456Z" + } }, "cell_type": "code", - "source": "#Exemple d'accès à une valeur\nnotes_dico = {\"Info\": 16, \"Communication\": 13, \"Anglais\": 20}\nprint(notes_dico[\"Communication\"])\nfor cle in notes_dico:\n print(cle, notes_dico[cle])", - "execution_count": 44, + "source": [ + "# Exemple d'accès à une valeur\n", + "notes_dico = {\"Info\": 16, \"Communication\": 13, \"Anglais\": 20}\n", + "print(notes_dico[\"Communication\"])\n", + "for cle in notes_dico:\n", + " print(cle, notes_dico[cle])" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "13\nInfo 16\nCommunication 13\nAnglais 20\n", - "name": "stdout" + "text": [ + "13\n", + "Info 16\n", + "Communication 13\n", + "Anglais 20\n" + ] } - ] + ], + "execution_count": 29 }, { "metadata": {}, "cell_type": "markdown", - "source": "Il existe des méthodes applicables sur un dictionnaire qui permettent de récupérer des collections de données en fonction de la méthode utilisée. Pour utiliser ces méthodes il suffit de spécifier le nom du dictionnaire visé suivi par la méthode à appliquer en séparant par le caractère *.* \n* **dico.keys()**: qui renvoie une collection contenant les clés comprises dans *dico*. \n* **dico.values()**: qui renvoie une collection contenant les valeurs comprises dans *dico*. \n* **dico.items()**: qui renvoie une collection de tuples contenant chacun les couples clés/valeurs comprises dans *dico*. \nL'ensemble de ces méthodes sont itérables. " + "source": [ + "Il existe des méthodes applicables sur un dictionnaire qui permettent de récupérer des collections de données en fonction de la méthode utilisée. Pour utiliser ces méthodes il suffit de spécifier le nom du dictionnaire visé suivi par la méthode à appliquer en séparant par le caractère `.`. \n", + "* `notes_dico.keys()`: qui renvoie une collection contenant les clés comprises dans `notes_dico`. \n", + "* `notes_dico.values()`: qui renvoie une collection contenant les valeurs comprises dans `notes_dico`. \n", + "* `notes_dico.items()`: qui renvoie une collection de tuples contenants chacun les couples clés/valeurs comprises dans `notes_dico`. \n", + "L'ensemble de ces méthodes sont itérables. " + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:56.425076Z", + "start_time": "2024-10-08T21:00:56.418297Z" + } }, "cell_type": "code", - "source": "#Exemple des méthodes à appliquer sur un dictionnaire\nnotes_dico = {\"Info\": 16, \"Communication\": 13, \"Anglais\": 20}\nprint(notes_dico.keys())\nprint(notes_dico.values())\nprint(notes_dico.items())", - "execution_count": 54, + "source": [ + "# Exemple des méthodes à appliquer sur un dictionnaire\n", + "notes_dico = {\"Info\": 16, \"Communication\": 13, \"Anglais\": 20}\n", + "print(notes_dico.keys())\n", + "print(notes_dico.values())\n", + "print(notes_dico.items())" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "dict_keys(['Info', 'Communication', 'Anglais'])\ndict_values([16, 13, 20])\ndict_items([('Info', 16), ('Communication', 13), ('Anglais', 20)])\n", - "name": "stdout" + "text": [ + "dict_keys(['Info', 'Communication', 'Anglais'])\n", + "dict_values([16, 13, 20])\n", + "dict_items([('Info', 16), ('Communication', 13), ('Anglais', 20)])\n" + ] } - ] + ], + "execution_count": 30 }, { "metadata": {}, @@ -617,31 +1018,57 @@ }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:56.569721Z", + "start_time": "2024-10-08T21:00:56.562217Z" + } }, "cell_type": "code", - "source": "#Exemple des méthodes à appliquer sur un dictionnaire\nnotes_dico = {\"Info\": 16, \"Communication\": 13, \"Anglais\": 20}\nfor couple in notes_dico.items():\n print(couple)", - "execution_count": 53, + "source": [ + "# Exemple des méthodes à appliquer sur un dictionnaire\n", + "notes_dico = {\"Info\": 16, \"Communication\": 13, \"Anglais\": 20}\n", + "for couple in notes_dico.items():\n", + " print(couple)" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "('Info', 16)\n('Communication', 13)\n('Anglais', 20)\n", - "name": "stdout" + "text": [ + "('Info', 16)\n", + "('Communication', 13)\n", + "('Anglais', 20)\n" + ] } - ] + ], + "execution_count": 31 }, { "metadata": {}, "cell_type": "markdown", - "source": "Il existe également des méthodes permettant de supprimer des couples cles/valeurs présents dans le dictionnaire. \n|Méthode|Description|\n|-|-|\n|pop()|Supprime l'élément dont la clé est spécifiée en paramètre et renvoie la valeur|\n|popitem()|Supprime le dernier élément ajouté au dictionnaire et renvoie le couple|\n|del()|Supprime l'élément dont la clé est spécifiée en paramètre|\n|clear()|Supprime tous les éléments du dictionnaire|\n" + "source": [ + "Il existe également des méthodes permettant de supprimer des couples clés/valeurs présentes dans le dictionnaire. \n", + "\n", + "| Méthode | Description |\n", + "|-----------|--------------------------------------------------------------------------------|\n", + "| `pop` | Supprime l'élément dont la clé est spécifiée en paramètre et renvoie la valeur |\n", + "| `popitem` | Supprime le dernier élément ajouté au dictionnaire et renvoie le couple |\n", + "| `del` | Supprime l'élément dont la clé est spécifiée en paramètre |\n", + "| `clear` | Supprime tous les éléments du dictionnaire |\n" + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:56.639525Z", + "start_time": "2024-10-08T21:00:56.630154Z" + } }, "cell_type": "code", "source": [ - "#Exemple de suppression d'éléments dans un dictionnaire\n", + "# Exemple de suppression d'éléments dans un dictionnaire\n", "notes_dico = {\"Info\": 16, \"Communication\": 13, \"Anglais\": 20}\n", "print(notes_dico.popitem())\n", "print(notes_dico)\n", @@ -653,39 +1080,61 @@ "notes_dico.clear()\n", "print(notes_dico)" ], - "execution_count": 62, "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "('Anglais', 20)\n{'Info': 16, 'Communication': 13}\n16\n{'Communication': 13}\n{}\n{}\n", - "name": "stdout" + "text": [ + "('Anglais', 20)\n", + "{'Info': 16, 'Communication': 13}\n", + "16\n", + "{'Communication': 13}\n", + "{}\n", + "{}\n" + ] } - ] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "***\n#### ***Exercice 7***\n\n**€€€ La monnaie SVP €€€** \nUn distributeur de banque dispose de billets de 10, 20, 50, 100, 200 et 500€. On suppose que la banque ne connaît pas la crise et possède donc un nombre illimité de billets). \nÉcrire un script Python qui demande la somme désirée par l'utilisateur et propose une répartition **sous forme de dictionnaire** en proposant le moins de billets possibles. Dans le cas où la banque ne peut pas donner l'intégralité de la somme souhaitée, elle distribue le montant possible et spécifie à l'utilisateur le montant manquant. \n*Exemple: 57€ demandé = 50€ x 1. Les 7€ manquants ne peuvent pas être distribués.* \n\n- Attention au choix des clés et valeurs dans le dictionnaire\n- Attention aux commentaires\n- Attention aux noms de variables. \n*Faites valider votre script ainsi que son exécution.*" + ], + "execution_count": 32 }, { "metadata": {}, "cell_type": "markdown", - "source": "***\n#### ***Exercice 8***\n\n**Moyenne !** \nÉcrire un script Python qui demande à l'utilisateur de saisir son prénom et ses notes dans les matières suivantes: \n* Scripting\n* Python\n* Code source \n\nPrésentez les résultats sous forme de dictionnaire faisant intervenir des couples clés/valeurs où la clé est le prénom de l'élève et la valeur est elle-même un dictionnaire. Ce sous-dictionnaire intègre également des couples clés/valeurs où la clé représente la matière et la valeur est une liste des notes dans la matière concernée. \nUne fois le dictionnaire de chaque étudiant créé vous avez constituez votre base de données. Complétez alors votre script pour calculer la moyenne dans chaque matière d'un étudiant, dont le prénom a été saisi par l'utilisateur, ainsi que sa moyenne générale. *On suppose que toutes les matières ont le même coefficient*. \n\n- Attention aux commentaires\n- Attention aux noms de variables. \n*Faites valider votre script ainsi que son exécution.*" + "source": [ + "***\n", + "#### ***Exercice 8***\n", + "\n", + "**Moyenne !** \n", + "Écrire un script Python qui demande à l'utilisateur de saisir son prénom et ses notes dans les matières suivantes : \n", + "* Scripting\n", + "* Python\n", + "* Code source \n", + "\n", + "Présentez les résultats sous forme de dictionnaire faisant intervenir des couples clés/valeurs où la clé est le prénom de l'élève et la valeur est elle-même un dictionnaire. Ce sous-dictionnaire intègre également des couples clés/valeurs où la clé représente la matière et la valeur est une liste des notes dans la matière concernée. \n", + "Une fois le dictionnaire de chaque étudiant créé vous avez constituez votre base de données. Complétez alors votre script pour calculer la moyenne dans chaque matière d'un étudiant, dont le prénom a été saisi par l'utilisateur, ainsi que sa moyenne générale. *On suppose que toutes les matières ont le même coefficient*. \n", + "\n", + "- Attention aux commentaires\n", + "- Attention aux noms de variables. \n", + "*Faites valider votre script ainsi que son exécution.*" + ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:56.781251Z", + "start_time": "2024-10-08T21:00:56.776955Z" + } }, "cell_type": "code", "source": [ - "#Exemple de dictionnaire à réaliser pour l'exercice 8\n", + "# Exemple de dictionnaire à réaliser pour l'exercice 8\n", "etudiant_dico = {\"Pierre\": {\"Scripting\": [12, 10],\n", " \"Python\": [18],\n", " \"Code source\": [15, 18]}}\n", - "#Ce dictionnaire doit être complété avec les infos saisies par l'utilisateur" + "# Ce dictionnaire doit être complété avec les infos saisies par l'utilisateur" ], - "execution_count": 66, - "outputs": [] + "outputs": [], + "execution_count": 33 }, { "metadata": {}, @@ -697,42 +1146,73 @@ "cell_type": "markdown", "source": [ "Les objets de type *set* représentent un autre type d'ensembles. La particularité des sets est qu'ils sont modifiables. Il existe également des sets non modifiables appelés *frozenset*. On retrouve alors les mêmes différences qu'entre les listes (modifiables) et les tuples (non modifiables). Les données sont **non ordonnées** et **sans doublons**. \n", - "Attention, un *set* se déclare avec des *{}* comme un dictionnaire. Au moment de l'initialisation il est nécessaire de spécifier le contenu du set ou de spécifier son type. En effet, un set vide est un objet de type dictionnaire !\n", + "Attention, un *set* se déclare avec des `{}` comme un dictionnaire. Au moment de l'initialisation il est nécessaire de spécifier le contenu du set ou de spécifier son type. En effet, un objet vide déclaré avec `{}` de type dictionnaire ! Il faut le déclarer avec `set()`.\n", "\n", "Une des particularités est qu'il ne peut contenir qu'une seule fois une même valeur.\n", "Il est donc pratique pour éliminer les doublons d'une liste.\n", - "Mais pour cela les éléments du set doivent être hashables... Pourquoi?" + "Mais pour cela les éléments du set doivent être hashables... Pourquoi ?" ] }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:56.876202Z", + "start_time": "2024-10-08T21:00:56.868788Z" + } }, "cell_type": "code", - "source": "#Exemple d'initiablisation d'un set\nmatieres_set = {\"Scripting\", \"Python\", \"Code Source\", \"Python\"}\nnotes_set = {}\nprint(type(matieres_set))\nprint(type(notes_set))\nnotes_set = set(notes_set)\nprint(type(notes_set))\nprint(matieres_set)", - "execution_count": 69, + "source": [ + "# Exemple d'initialisation d'un set\n", + "matieres_set = {\"Scripting\", \"Python\", \"Code Source\", \"Python\"}\n", + "notes_set = {}\n", + "print(type(matieres_set))\n", + "print(type(notes_set))\n", + "empty_set = set()\n", + "print(type(empty_set))\n", + "notes_set = set(notes_set)\n", + "print(type(notes_set))\n", + "print(matieres_set)" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "\n\n\n{'Scripting', 'Python', 'Code Source'}\n", - "name": "stdout" + "text": [ + "\n", + "\n", + "\n", + "\n", + "{'Python', 'Code Source', 'Scripting'}\n" + ] } - ] + ], + "execution_count": 34 }, { "metadata": { - "trusted": false + "trusted": false, + "ExecuteTime": { + "end_time": "2024-10-08T21:00:57.000817Z", + "start_time": "2024-10-08T21:00:56.995307Z" + } }, "cell_type": "code", - "source": "#Exemple d'initialisation d'un frozenset\nmatieres_set = frozenset({\"Scripting\", \"Python\", \"Code Source\", \"Python\"})\nprint(type(matieres_set))", - "execution_count": 70, + "source": [ + "# Exemple d'initialisation d'un frozenset\n", + "matieres_set = frozenset({\"Scripting\", \"Python\", \"Code Source\", \"Python\"})\n", + "print(type(matieres_set))" + ], "outputs": [ { + "name": "stdout", "output_type": "stream", - "text": "\n", - "name": "stdout" + "text": [ + "\n" + ] } - ] + ], + "execution_count": 35 } ], "metadata": { diff --git a/doc/image/exception.drawio b/doc/image/exception.drawio new file mode 100644 index 0000000..ab9a04f --- /dev/null +++ b/doc/image/exception.drawio @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/doc/image/exception.jpg b/doc/image/exception.jpg new file mode 100644 index 0000000..225de5e Binary files /dev/null and b/doc/image/exception.jpg differ diff --git a/doc/python.tex b/doc/python.tex index 31e6e47..77cf5db 100644 --- a/doc/python.tex +++ b/doc/python.tex @@ -556,20 +556,128 @@ \end{frame} + \section{Les mots clé}\label{sec:keyword} + + \begin{frame}[fragile]{Les mots clé Python\footnote{Python Keywords, \url{https://docs.python.org/3/reference/lexical_analysis.html\#keywords}}} + Python a ces mots clé~: + \begin{verbatim} +False await else import pass +None break except in raise +True class finally is return +and continue for lambda try +as def from nonlocal while +assert del global not with +async elif if or yield + \end{verbatim} + Nous les connaîtrons tous (ou quasi) à la fin de cette session~! + \end{frame} + + \section{Premiers pas}\label{sec:first-steps} \begin{frame}{Premiers pas}{Mes premières variables et algorithme} - Ouvrir dans Pycharm le notebook \url{https://github.com/DigicompClassesByPapIT/Python/blob/main/1_premiers_pas.ipynb}. + Ouvrir dans PyCharm le notebook téléchargé à l'adresse \url{https://github.com/DigicompClassesByPapIT/Python/blob/main/1_premiers_pas.ipynb}. \bigbreak Ce dernier expose des concepts de base comme~: \begin{itemize} \item Les variables \item Les opérateurs arithmétiques - \item Les opérations logiques \item Les commentaires \item Les types de base \end{itemize} \end{frame} + \section{Bases de la programmation}\label{sec:programming-basics} + + \begin{frame}{Bases de la programmation}{Plus d'opérateurs et branchements} + Ouvrir dans PyCharm le notebook téléchargé à l'adresse \url{https://github.com/DigicompClassesByPapIT/Python/blob/main/2_base_programmation.ipynb}. + \bigbreak + Ce dernier expose des concepts de base comme~: + \begin{itemize} + \item Les opérateurs logiques + \item Les opérations de comparaison + \item Les opérateurs binaires + \item Les opérateurs d'identité + \item Opérateurs d'appartenance + \item Opérateurs d'affectation + \item Branchements A.K.A, le branching, une partie du control flow + \end{itemize} + \end{frame} + + \begin{frame}{Bases de la programmation}{Les boucles} + Ouvrir dans PyCharm le notebook téléchargé à l'adresse \url{https://github.com/DigicompClassesByPapIT/Python/blob/main/3_boucles_iteratives.ipynb}. + \bigbreak + Ce dernier expose des concepts liés aux boucles~: + \begin{itemize} + \item Boucle \lstinline{while} liée à une condition d'arrêt + \item Boucle \lstinline{for} + \item Les instructions \lstinline{break} et \lstinline{continue} + \item Le \lstinline{else} dans une boucle + \item Les fonctions \lstinline{range} et \lstinline{enumerate} + \item Les fonctions \lstinline{sort} et \lstinline{sorted} + \item L'instruction \lstinline{map} + \item Les compréhensions de listes + \end{itemize} + \end{frame} + + \begin{frame}{Bases de la programmation}{Les erreurs et exceptions} + Ouvrir dans PyCharm le notebook téléchargé à l'adresse \url{https://github.com/DigicompClassesByPapIT/Python/blob/main/4_erreurs_exceptions.ipynb}. + \bigbreak + Ce dernier expose des concepts liés aux erreurs et exceptions~: + \begin{itemize} + \item Les erreurs qu'on ne peut pas \textit{catch} + \item Les exceptions built-in + \item Les instructions \lstinline{try} et \lstinline{except} + \item Créer ses propres exceptions + \end{itemize} + \end{frame} + + \begin{frame}{Bases de la programmation}{Les erreurs et exceptions} + Un programme ne doit pas directement crasher à cause d'une exception levée. + Les librairies et API doivent lever des exceptions pour signaler des erreurs au couches supérieur du programme que le GUI ou la CLI. + \bigbreak + \centering + \includegraphics[width=11cm]{image/exception} + \end{frame} + + \begin{frame}{Bases de la programmation}{Les fonctions} + Ouvrir dans PyCharm le notebook téléchargé à l'adresse \url{https://github.com/DigicompClassesByPapIT/Python/blob/main/5_fonctions.ipynb}. + \bigbreak + Ce dernier expose des concepts suivants~: + \begin{itemize} + \item Déclarations d'une fonction + \item Retour de valeurs + \item Fonction lambda + \item Les \textit{partials} + \item Décorateurs + \end{itemize} + \end{frame} + + \section{Types de données}\label{sec:data-types} + + \begin{frame}{Types de données}{Les itérables} + Ouvrir dans PyCharm le notebook téléchargé à l'adresse \url{https://github.com/DigicompClassesByPapIT/Python/blob/main/6_types_iterables.ipynb}. + \bigbreak + Ce dernier détail les types built-in itérables uniquement~: + \begin{itemize} + \item Les chaînes de caractères, \lstinline{str} + \item Les listes, \lstinline{list} + \item Les tuples, \lstinline{tuple} + \item Les dictionnaires, \lstinline{dict} + \item Les ensembles, \lstinline{set} + \end{itemize} + Il existe d'autres types pouvant contenir des collections comme les \lstinline{Queue}, les \lstinline{namedtuple}, les \lstinline{array} par exemple. + \end{frame} + + \begin{frame}{Types de données}{Les nombres} + Ouvrir dans PyCharm le notebook téléchargé à l'adresse \url{https://github.com/DigicompClassesByPapIT/Python/blob/main/7_types_numeriques.ipynb}. + \bigbreak + Ce dernier détail 2 types numériques built-in, les principaux~: + \begin{itemize} + \item Les entiers, \textit{integer} en anglais, \lstinline{int} + \item Les flottants, \textit{float} en anglais, \lstinline{float} + \end{itemize} + Il existe d'autres types pour travailler avec les nombres réels comme par exemple avec le module \lstinline{decimal} de la librairie standard. + \end{frame} \section{Licence CC}\label{sec:licence} diff --git a/les_fichiers.ipynb b/les_fichiers.ipynb index 936f79f..5870b63 100644 --- a/les_fichiers.ipynb +++ b/les_fichiers.ipynb @@ -647,7 +647,7 @@ "***Le juste prix*** \n", "L'ordinateur choisit aléatoirement un prix entre 30€ et 100€ compris (que des valeurs entières). \n", "L'utilisation (joueur) doit trouver la valeur en un minimum d'essais. \n", - "A chaque proposition du joueur, un message s'affichera: \n", + "À chaque proposition du joueur, un message s'affichera: \n", "- C'est plus !\n", "- C'est moins ! \n", "- Vous avez gagné ! \n", diff --git a/les_fonctions.ipynb b/les_fonctions.ipynb deleted file mode 100644 index 7a18a12..0000000 --- a/les_fonctions.ipynb +++ /dev/null @@ -1,592 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Programmation Python 3 - Les fonctions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Définition" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La manière dont un développeur va écrire son code est un paradigme de programmation. Ainsi, un paradigme de programmation est une approche logique qu'un développeur va adopter pour résoudre son problème. \n", - "\n", - "Depuis que vous travailler en langage Python, vous utilisez un paradigme impératif, en effet les étapes d'instruction se suivent jusqu'à aboutir au résultat attendu. Cette méthode de résolution consiste à réaliser des instructions les unes à la suite des autres. C'est un approche efficace pour les programmes/scripts courts avec peu d'instructions. Le code impératif (aussi appelé code procédural) n'est pas réutilisable. \n", - "\n", - "Ainsi, il existe d'autres paradigmes permettant de réaliser les insctructions de la manière dont nous les souhaitons, comme par exemple le paradigme objet ou le paradigme fonctionnel. \n", - "\n", - "- La programmation orientée objet consiste à modéliser son code sous forme d'objets ayant des propriétés (appelées attributs) et des capacités d'action (appelées méthodes) qui intégragissent entre eux plutôt qu'une séquence d'instructions. \n", - " \n", - "- La programmation fonctionnelle permet de décomposer un problème en un ensemble de fonctions. Dans l'idéal, les fonctions produisent des sorties à partir des entrées et ne possèdent pas d'état interne qui soit susceptible de modifier la sortie pour une entrée donnée. Le paradigme fonctionnel cherche à éviter au maximum les effets de bord, en programmation fonctionnelle on va éviter de modifier les valeurs associées à des variables globales. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "En programmation, une approche efficace d'un problème complexe revient à le décomposer en plusieurs sous-problèmes plus simples qui puevent eux-mêmes être décomposer à leur tout jusqu'à aboutir à un des sous-sous-sous...problèmes simples. \n", - "Il est également fréquent de vouloir répéter une même séquence d'instructions, à plusieurs reprises sans pour autant avoir à réécrire les insctructions concernées; c'est le rôle des **fonctions**. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Généralités" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "En plus de permettre une répétition d'instructions autant de fois que désiré, les fonctions rendent le code plus lisible et plus clair. \n", - "Vous avez déjà utilisé des fonctions pré-programmées telles que ***len()***, ***range()*** ou même la méthode ***randint()*** du module *random*. \n", - "Lors de l'utilisation de ces fonctions vous avez passé aucune, une ou plusieurs variables ou valeurs entre les parenthèses, comme par exemple ***len(liste)***, ***range(2, 9, 2)*** ou ***randint(1, 100)***. Ces varaiables ou valeurs sont appelées des **arugments** et sont nécessaires à la fonction afin que celle-ci s'exécute correctement. Les argument peuvent être de n'importe quel type et sont propres à la fonction utilisée. Il est possible qu'une fonction n'ait pas besoin d'arguments. \n", - "\n", - "Après l'exécution de la fonction, celle-ci peut renvoyer aucune, une ou plusieurs variables ou valeurs en sortie comme par exemple ***len(liste)*** qui renvoie une donnée numérique de type entier égale à la longueur de l'argument, ici *liste*, ou liste.***append(4)*** qui ajoute l'argument à la fin de *liste* mais ne renvoie rien. \n", - "\n", - "En général, une fonction effectue une tâche **unique** et **précise**. Il vaut mieux décomposer le programme en *X* sous-tâches appelées fonctions plutôt que de créer moitié moins de fonctions qui à elles-seules réaliser plusieurs tâches. Le code en sera d'autant plus lisible et clair. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Déclaration" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Pour pouvoir utiliser une fonction il faut réaliser deux actions essentielles:\n", - "1. Déclaration de la fonction\n", - "2. Appel de la fonction \n", - "\n", - "L'appel de la fonction peut être réalisé dans la fonction elle-même, dans une autre fonction, ou dans le programme principal (il s'agit de la partie du code qui est exécuté quand le programme est lance. le programme principal se situe après les définitions de fonctions. \n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Pour déclarer ou définir une fonction, il faut utiliser le mot-clé **def** suivi du nom que l'on souhaite donner à la fonction. **Attention, comme pour les noms de variables il est recommandé de donner des noms significatifs**. \n", - "\n", - "La syntaxe d'écriture ppur déclarer une fonction est la suivante: " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def nomSignificatifDeLaFonction(argument1, argument2, ...):\n", - " instruction1\n", - " instruction2\n", - " instruction3\n", - " ..." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Il est important de penser aux éléments suivants lors de la définition d'une fonction: \n", - "* Ne pas oublier le mot-clé **def** en début de la définition\n", - "* Donner un nom significatif à la fonction\n", - "* Ne pas oublier les parenthèses même si il n'y pas d'arugments !\n", - "* Ne pas oublier les **:** à la fin de l'instruction de définition\n", - "* Ne pas oublier l'**indentation** pour les instructions qui composent la fonction. " - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "#Exemple de déclaration d'une fonction sans argument\n", - "#----- Début Declaration de fonctions -----\n", - "def message_de_bienvenue():\n", - " print(\"Bienvenue dans le chapitre sur les fonctions\")\n", - "\n", - "#----- Fin Declaration de fonctions -----" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "En exécutant la cellule ci-dessus on constate que rien ne se passe, en effet seule la définition de la fonction a été réalisée. L'appel de la fonction est absent. " - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Bienvenue dans le chapitre sur les fonctions\n" - ] - } - ], - "source": [ - "#Exemple de déclaration d'une fonction sans argument\n", - "#----- Début Declaration de fonctions -----\n", - "def message_de_bienvenue():\n", - " print(\"Bienvenue dans le chapitre sur les fonctions\")\n", - "\n", - "\n", - "#----- Fin Declaration de fonctions -----\n", - "\n", - "#----- Début Programme Principal -----\n", - "message_de_bienvenue()\n", - "#----- Fin Programme Principal -----" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Après appel de la fonction, on constate bien son exécution. \n", - "Lors de l'appel de la fonction, il faut veiller à:\n", - "* Appeler la fonction avec son nom correctement saisi\n", - "* Ne pas oublier les parenthèses même si il n'y a pas d'arguments\n", - "* Si il y en a, ne pas oublier les arguments dans les parenthèses" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Bonjour\n", - "Bonjour\n", - "Bonjour\n" - ] - } - ], - "source": [ - "#Exemple de déclaration d'une fonction avec arguments\n", - "#----- Début Declaration de fonctions -----\n", - "def message_de_bienvenue(message, repetitions):\n", - " for i in range(repetitions):\n", - " print(message)\n", - "\n", - "\n", - "#----- Fin Declaration de fonctions -----\n", - "\n", - "#----- Début Programme Principal -----\n", - "mon_message = \"Bonjour\"\n", - "nb_repetitions = 3\n", - "message_de_bienvenue(mon_message, nb_repetitions)\n", - "#----- Fin Programme Principal -----" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Les exemples que nous venons de traiter seront plus considérées comme des ***procédures*** et non de \"vraies\" fonctions. En effet, une fonction doit renvoyer une valeur lorsque celle termine de s'exécuter, ce qui engnedre que dans le programme principal la valeurs retournée doit être assignée à une variable. \n", - "\n", - "C'est l'instruction **return** qui permet de renvoyer une ou plusieurs valeurs. " - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "124.53\n", - "67.19\n" - ] - } - ], - "source": [ - "#Exemple de déclaration d'une fonction retournant une valeur\n", - "#----- Début Declaration de fonctions -----\n", - "def additionner(nb1, nb2=30.0):\n", - " res = nb1 + nb2\n", - " return res\n", - "\n", - "\n", - "#----- Fin Declaration de fonctions -----\n", - "\n", - "#----- Début Programme Principal -----\n", - "val1 = 37.19\n", - "val2 = 87.34\n", - "ex1_somme = additionner(val1, val2)\n", - "print(ex1_somme)\n", - "ex2_somme = additionner(val1)\n", - "print(ex2_somme)\n", - "#----- Fin Programme Principal -----" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Dans l'exemple présenté ci-dessus, on constate donc que la varible *ex1_somme* prend la valeur retournée par le premier appel de fonction de *additionner* avec les valeurs *37.19* et *87.34*. \n", - "Pour la variable *ex2_somme* celle-ci prend la valeur retournée par le second appel de fonction mais où un seul paramètre n'est spécifié alors que deux sont nécessaires comme mentionnée dans la définition de la fonction. \n", - "**Dans la défintion d'une fonction, il est possible de définir une valeur par défaut des arguments**. Cette valeur définit par défaut n'est pas prioritaire et est ainsi ignorée lorsque la valeur est spécifiée lors de l'appel de fonction. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Afin de rendre le code plus lisible et clair, il est possible d'annoter les fonctions. Pour cela, chaque paramètre va être suivi de son type, ainsi que le type retournée par la fonction à la fin de son exécution. " - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "124.53\n", - "67.19\n" - ] - } - ], - "source": [ - "#Exemple de déclaration d'une fonction avec annotations\n", - "#----- Début Declaration de fonctions -----\n", - "def additionner(nb1: float, nb2: float = 30.0) -> float:\n", - " res = nb1 + nb2\n", - " return res\n", - "\n", - "\n", - "#----- Fin Declaration de fonctions -----\n", - "\n", - "#----- Début Programme Principal -----\n", - "val1 = 37.19\n", - "val2 = 87.34\n", - "ex1_somme = additionner(val1, val2)\n", - "print(ex1_somme)\n", - "ex2_somme = additionner(val1)\n", - "print(ex2_somme)\n", - "#----- Fin Programme Principal -----" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Dans l'exemple ci-dessus, on constate donc que les deux arguments doivent être tous les deux type *float* (il faut séparer le nom de la variable du type avec *:*). Le type retourné par la fonction doit lui être spécifié entre les arguments et le caractère *:* en utilisant les caractères *->* suivi du type. \n", - "***Attention, l'annotation de fonctions est optionnelle, ainsi lors de l'appel de la fonction le paramètre n'est pas du même type que celui mentionné dans la définition de la fonction, aucune erreur ne sera généré. C'est à la charge du développeur de vérifier que les types des paramètres sont bien conformes***. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Variables globales et locales" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La portée des variables est un point important dans le paradigme fonctionnel. En effet, en fonction de l'endroit dans le script où les variables sont définies va être déterminant sur leur utilisation. En Python, une variable peut avoir une portée (espaces dans lesquels la variable est accessible) **locale** ou une portée **globale**. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- Une variable **globale** peut être accessible n'importe où dans le script. \n", - "- Une variable **locale** est accessible uniquement à l'intérieur d'un bloc de code. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**En Python, si une variable n'est pas modifiée dans une fonction mais seulement lue, elle est implicitement considérée comme globale. Si une valeur lui est affectée, elle est considérée comme locale (sauf si elle est explicitement déclaré globale)**. \n", - "\n", - "L'exemple ci-dessous illustre la règle présentée ci-dessus: " - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "124.53\n", - "67.19\n", - "Affichage valeur de la variable globale res: 0\n" - ] - } - ], - "source": [ - "# Exemple de déclaration d'une variable globale\n", - "#----- Début déclaration variable globale -----\n", - "res = 0\n", - "\n", - "\n", - "#----- Fin déclaration variable globale -----\n", - "\n", - "#----- Début Declaration de fonctions -----\n", - "def additionner(nb1: float, nb2: float = 30.0) -> float:\n", - " res = nb1 + nb2\n", - " return res\n", - "\n", - "\n", - "#----- Fin Declaration de fonctions -----\n", - "\n", - "#----- Début Programme Principal -----\n", - "val1 = 37.19\n", - "val2 = 87.34\n", - "ex1_somme = additionner(val1, val2)\n", - "print(ex1_somme)\n", - "ex2_somme = additionner(val1)\n", - "print(ex2_somme)\n", - "print(\"Affichage valeur de la variable globale res: \", res)\n", - "#----- Fin Programme Principal -----" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Dans l'exemple on constate que la variable *res* est déclarée en variable globale. Dans le fonction *additionner*, la variable *res* se voit affecter une valeur. Cette variable porte le meme nom que la variable globale. La variable *res* définit dans la fonction est donc une variable locale et n'est accessible qu'au sein de cette fonction. Pour preuve, à la fin du programme un affichage de la variable *res* est demandé et c'est la valeur 0 qui est affichée, cette valeur étant celle assignée par défaut au moment de la déclaration de la variable globale, la valeur n'a donc pas été modifiée au sein de la fonction. \n", - "\n", - "Si le souhait est de modifier la valeur de la variable globale il faut alors le déclarer explicitement comme présenté ci-dessous: " - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "124.53\n", - "67.19\n", - "Affichage valeur de la variable globale res: 67.19\n" - ] - } - ], - "source": [ - "# Exemple de déclaration d'une variable globale\n", - "#----- Début déclaration variable globale -----\n", - "res = 0\n", - "\n", - "\n", - "#----- Fin déclaration variable globale -----\n", - "\n", - "#----- Début Declaration de fonctions -----\n", - "def additionner(nb1: float, nb2: float = 30.0) -> float:\n", - " global res\n", - " res = nb1 + nb2\n", - " return res\n", - "\n", - "\n", - "#----- Fin Declaration de fonctions -----\n", - "\n", - "#----- Début Programme Principal -----\n", - "val1 = 37.19\n", - "val2 = 87.34\n", - "ex1_somme = additionner(val1, val2)\n", - "print(ex1_somme)\n", - "ex2_somme = additionner(val1)\n", - "print(ex2_somme)\n", - "print(\"Affichage valeur de la variable globale res: \", res)\n", - "#----- Fin Programme Principal -----" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "L'instruction *global* permet de spécifier que la variable qui suit est une variable globale, pour preuve à la fin de l'exécution du script on constate que la valeur finale de la variable globale *res* n'est plus égale à 0 mais au résultat de l'addition opérée au sein de la fonction. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": "Toutefois, l'utilisation de l'instruction *global* est déconseillée car ce n'est pas une bonne pratique et doit dans la limite du possible être évitée. Si le but est de modifier le contenu d'une variable globale, il est préférable d'utiliser la valeur retournée par la fonction.\n" - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Docstring" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Un script Python sera plus souvent lu que écrit, en ce sens il est primordial de rendre son contenu clair, lisible afin de faciliter sa lecture et sa compréhension. En plus des noms de variables, fonctions qui doivent être significatifs, il est opportun de mettre des commentaires à tout script Python ainsi de que des spécifications à chaque fonction déclarée. Cette spécification se présente sous la forme de *docstring*. Cette documentation se présente sous la forme d'un paragraphe entouré des caractères *\"\"\"* et se situe au tout début de la définition de la fonction. \n", - "Il s'agit d'une spécification textuelle et doit à minima contenir les éléments suivants: \n", - "- Une phrase présentant l'objectif de la fonction. Cette phrase doit permettre de répondre à la question \"A quoi sert cette fonction?\". \n", - "- Préciser les types de données (arguments) ainsi que leur utilité. \n", - "- Préciser les types de sorties (données retournées) ainsi que leur utilité. \n", - "\n", - "Un exemple ci-dessous vous présentant un format RST (le plus classique) de docstring: " - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "124.53\n", - "0\n", - "Affichage valeur de la variable globale res: 0\n" - ] - } - ], - "source": [ - "# Exemple de déclaration d'une variable globale\n", - "#----- Début déclaration variable globale -----\n", - "res = 0\n", - "\n", - "\n", - "#----- Fin déclaration variable globale -----\n", - "\n", - "#----- Début Declaration de fonctions -----\n", - "def additionner(nb1: float, nb2: float = 30.0) -> float:\n", - " \"\"\"Calcul d'une somme entre deux nombres\n", - " \n", - " :param nb1: Premier nombre à additionner, type float\n", - " :param nb2: Second nombre à additionner, type float (defaut: 30.0)\n", - " \n", - " return res: Résultat de l'addition, type float\n", - " \n", - " \"\"\"\n", - " res = nb1 + nb2\n", - " return res\n", - "\n", - "\n", - "#----- Fin Declaration de fonctions -----\n", - "\n", - "#----- Début Programme Principal -----\n", - "val1 = 37.19\n", - "val2 = 87.34\n", - "ex1_somme = additionner(val1, val2)\n", - "print(ex1_somme)\n", - "ex2_somme = additionner(val1)\n", - "print(res)\n", - "print(\"Affichage valeur de la variable globale res: \", res)\n", - "#----- Fin Programme Principal -----" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "***\n", - "#### ***Exercice 1***" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "***Des lettres et des lettres !*** \n", - "\n", - "Écrire un script Python en adoptant le paradigme fonctionnel et permettant au joueur de jouer à une version simplifiée du Scrabble. \n", - "Le joueur se voit attribuer 7 lettres au hasard. Ce dernier doit ensuite former un mot avec les lettres à sa disposition. Si le mot proposé aprle joueur est possible c'est-à-dire qu'il peut être écrit à partir des lettres à sa disposition, le joueur gagne un nombre de points égale au nombre de lettres du mot. Dans le cas contraire si pas de proposition ou si le mot ne peut pas être écrit dans sa totalité avec les lettres à la disposition du joueur, ce dernier se voit attribué le score de 0. \n", - "\n", - "*Exemple:* \n", - "- Lettres à la disposition du joueur: NBJORUO\n", - "- Proposition du joueur: JOUR -> Score = 4\n", - "- Autre proposition du joueur: SALUT -> Score = 0 \n", - " \n", - "1. Attention aux commentaires\n", - "2. Attention aux docstring\n", - "3. Attention aux noms de variables. \n", - "\n", - "*Faites valider votre script ainsi que son exécution.* \n", - "***" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### ***Exercice 2***" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "En vous appuyant sur le script de l'exercice 1, écrire un script Python en adoptant le paradigme fonctionnel et permettant de jouer au scrabble. \n", - "Les valeurs des lettres sont les suivantes: \n", - "- 0 point: Joker (permet de remplacer n'importe quelle lettre)\n", - "- 1 point: E, A, I, N, O, R, S, T, U, L\n", - "- 2 points: D, G, M\n", - "- 3 points: B, C, P\n", - "- 4 points: F, H, V\n", - "- 8 points: J, Q\n", - "- 10 points: K, W, X, Y, Z \n", - "\n", - "1. Attention aux commentaires\n", - "1. Attention aux docstring\n", - "1. Attention aux noms de variables. \n", - "\n", - "*Faites valider votre script ainsi que son exécution.* \n", - "***" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.5" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -}