<jupyter_start><jupyter_text>[pour Statistique et Science des Données](https://github.com/wikistat/Intro-Python)  Introduction à  pour Calcul Scientifique - Statistique **Résumé** Présentation de jupyter notebook et des bases de python; utilisation d'un notebook, types de données, structures élémentaires de données, structures de contrôle.  A - Python et jupyter notebook Python exécute programmes ou scripts, programmes qui peuvent être pré-compilés pour plus d'efficacité. Ce langage s'exécute également à l'aide d'un interprète de commande (`IDLE`) ou {`IPython`) de manière interactive.  En situation pédagogique, c'est l'utilisation et la réalisation d'un *notebook Ipython* ou plutôt maintenant *Jupyter* qui est privilégiée à partir d'un simple navigateur.Les commandes sont regroupées dans des cellules suivies de leur résultat après exécution. Ces résultats et commentaires sont  stockés dans un fichier spécifique `.ipynb` et sauvegardés. Les commandes LaTeX sont acceptées pour intégrer des formules, la mise en page est assurée par des balises HTML ou [*Markdown*](http://fr.wikipedia.org/wiki/Markdown). La commande de sauvegarde permet également d'extraire les seules commandes Python dans un fichier d'extension `.py`. C'est une façon simple et efficace de conserver tout l'historique d'une analyse pour en faire une présentation ou créer un tutoriel. Le notebook peut être en effet chargé  sous un autre format: page `html`, fichier `.pdf` ou diaporama.Le projet [Jupyter](http://jupyter.org/) propose cet environnement de notebook pour beaucoup de langages (Python, Julia, Scala...) dont R. Il devient un outil indispensable pour assurer simplement la *reproductibilité* des analyses. Une fois le notebook ouvert, - Entrer des commandes Python dans une cellule,- Cliquer sur le bouton d'exécution de la cellule.- Ajouter une ou des cellules de commentaires et balises HTML ou [Markdown](http://fr.wikipedia.org/wiki/Markdown).Itérer l'ajout de cellules. Une fois l'exécution terminée:- Sauver le notebook `.ipynb` - Charger éventuellement une version `.html` pour une page web.- Charger le fichier `.py` regroupant les commandes python pour une version opérationnelle.**Attention** Un notebook de IPython ou Jupyter est un outil de travail exploratoire efficace et un compte rendu nécessairement *chronologique* d'exécution.  1. Gestion des cellulesUn notebook est composé de différentes cellules. Quand vous cliquez sur ce texte par exemple, les limites de la cellule actuelle apparaissent!  1.1.  Type de cellulesIl existe différents types de cellules.  1.1.a- Cellule markdown Cette case est un commentaire Les cellules en markdown permettent d'intégrer des explications au code, d'expliquer ce que l'on fait au fur et à mesure de l'avancement du notebook.Ils peuvent notamment présenter les parties de code difficiles à appréhender, ou expliquer les retours de code. D'ailleurs, ce cours est intégré à un notebook à l'aide des cellules markdown :-) Le *markdown* permet d'inclure des images stockées localement (ou en ligne!) dans vos cellules!![rennes](https://www.univ-rennes1.fr/sites/www.univ-rennes1.fr/files/logo_ur1_gris.png)Vous pouvez également formater le texte de vos cellules grâce à des balises:- En rouge et en petit ou en vert et en grand- En **gras** ou en *italique*- Vous pouvez mettre en forme des maths : $ \sum_{\forall i}{x_i^{2}} $Pour passer une cellule en markdown, faîtes défiler le menu déroulant en dessous de 'Widgets' jusqu'à la valeur 'markdown'.Raccourci pour passer une cellule en markdown : m  1.1.b - Cellule de code python<jupyter_code>print("Celle-ci est une ligne de code")<jupyter_output>Celle-ci est une ligne de code<jupyter_text>Les cellules de code contiendront le code de vos programmes. Les retours de code (print, affichage de variable, etc.) s'affichent en-dessous de la cellule au fil de l'exécution du code.Pour passer une cellule en code, faîtes défiler le menu déroulant en dessous de 'Widgets' jusqu'à la valeur 'code'.Raccourci pour passer une cellule en code : y  1.2. Exécution de cellulesPour interpréter du code python, ou rendre du markdown, il faut exécuter les cellules. Vous pouvez exécuter les cellules avec la commande run, présente dans le panel situé au-dessus du notebook. Ou vous pouvez utiliser les raccourcis ci-dessous :- Raccourci pour exécuter la cellule : ctrl + enter- Raccourci pour exécuter la cellule et passer à la prochaine cellule : shift + enter  1.3. Modes  1.3.a - Mode commande Le mode commande est un mode "général", dédié à la gestion de cellule. En mode commande, les flèches directionnelles vous permettent de naviguer de cellule en cellule.Pour passer en mode commande; cliquez "dans la marge", du côté gauche de la cellule.Exécuter une cellule vous fait passer en mode commande.  1.3.b - Mode édition Le mode édition vous permet d'éditer le contenu des cellules. Il permet notamment de modifier le code ou le markdown.En mode édition, les flèches directionnelles vous font passer d'une ligne à l'autre.**Tips** : Si vous êtes en mode édition sur la dernière ligne d'une cellule, appuyer sur bas vous fera basculer en mode édition dans la cellule du bas.Pour passer en mode édition;- markdown exécuté : double-cliquez sur la cellule- code ou markdown non exécuté : cliquez dans la cellule  1.4. Ajout et suppression 1.4.a- AjoutVous êtes à court de cases? Appuyez sur le '+' du panel du haut pour insérer une case.Raccourci pour l'ajout : A, en mode commande 1.4.b- Suppression**ATTENTION** : Une fois supprimée, une case ne peut pas être récupérée (sauf si vous versionnez le code).Vous pouvez couper la case pour la supprimer.Raccourci pour l'ajout : X, en mode commande  1.5. Changer l'ordre des casesUtilisez les flèches du panel !  1.6. Sélectionner plusieurs casesUne fois en mode commande sur une cellule, appuyez sur shift, et cliquez sur une autre cellule pour sélectionner toutes les cellules au milieu.  1.7. Copier-coller les casesRaccourcis:- Copier : ctrl-c- Coller : ctrl-v  2. Gestion du noyau Le noyau (ou kernel) contient l'interpréteur python qui exécute votre code, et liste en mémoire vos variables.  2.1. Interrupt Dans le cas d'une cellule qui contient une boucle infinie, ou qui met trop de temps à s'exécuter, il peut être intéressant d'interrompre son exécution. Dans ce cas, cliquez sur le menu 'Kernel', puis 'Interrupt'.  2.2. Restart Redémarrer votre kernel effacera toutes les données liées à l'exécution de python.  2.3. Kernels pour d'autres langages Il existe des kernels qui interprètent d'autres langages, comme R ou Julia.  3. WidgetsLe framework de Jupyter permet d'intégrer des widgets aux notebooks, afin que l'utilisateur puisse interagir avec votre code.<jupyter_code>from ipywidgets import interact
import ipywidgets as widgets
@interact(checked = widgets.Checkbox(value = False, 
                               description = 'Click me !', 
                               disabled = False))
def check_the_box(checked):
    if checked:
        print("Well done!")
@interact(bonjour = widgets.Textarea(value = '', 
                                       description = 'Write hello there ->', 
                                       disabled = False,
                                       layout = widgets.Layout(width='500px', height = '30px'),
                                       style = {'description_width': 'initial'}))
def say_hello(bonjour):
    if bonjour == "hello":
        print("Well done!")
print("Grab the button and slide it horizontally!")
@interact(id = widgets.IntSlider(min = 1, max = 10, step = 1, value = 1, 
                                         description = 'Change id value to 3 - id', 
                                         layout = widgets.Layout(width='800px'),
                                         style = {'description_width': 'initial'}))
def say_hello(id):
    if id == 3:
        print("Well done!")<jupyter_output>Grab the button and slide it horizontally!<jupyter_text>4. Les dangers du notebook 4.1. L'ordre d'exécution des cellules<jupyter_code>a = 3
a = 5
a<jupyter_output><empty_output><jupyter_text>L'utilisateur peut exécuter les cellules dans l'ordre qu'il veut. Cependant, cela peut créer des surprises; pour les trois cellules du dessus (appelons-les c1, c2 et c3 de haut en bas), c1-c2-c3 rendra 5 alors que c2-c1-c3 rendra 3...Prenez garde à (1) soit mémoriser la valeur de vos variables (2) soit faire attention à l'ordre d'exécution!  4.2.  Suppression de celluleJ'insiste, car vous vous ferez avoir à un moment si vous continuez à utiliser les notebooks. Supprimer la mauvaise cellule peut vous faire perdre des minutes, des heures, ou des jours de travail... ce contenu est important  4.3. - Voir I don't like notebooks  4.4. Google colab : https://colab.research.google.com/notebooks/intro.ipynb  B - Quelques exemples pour démarrer avec python  1. Types de données  1.1. Scalaires et chaînesLa déclaration des variables est implicite ({integer, float, boolean, string), la syntaxe est très proche de celle de R mais il n'y a pas de type `factor`.<jupyter_code>a=3  # est un entier
b=1. # est un flottant
# Attention:
a/2  # a pour résultat 1.5 en Python 3.4 
     # mais 1 en 2.7<jupyter_output><empty_output><jupyter_text>Opérateurs de comparaison : `==, >, <, !=` de résultat booléen.<jupyter_code># Comparaison
a==b  
#  affichage et type des variables
type(a)
# Chaîne de caractère
a='bonjour '
b='le '
c='monde'
a+b+c<jupyter_output><empty_output><jupyter_text>Attention à l'encodage des caractères. Ce n'est pas le même en python 2 (ascii) et python 3 (utf-8). Ce n'est pas fait dans ces exemples élémentaires mais il est vivement recommandé de gérer systématiquement des textes complexes avec caractères spéciaux (accents, guillements...) en utf-8<jupyter_code>a=u'bonjour' # encodage utf-8
type(a)
a='bonjour'  # encodage ascii
type(a)<jupyter_output><empty_output><jupyter_text>Affectation des indicesDes expressions telles que x = x + 1 ou x = x - 2 apparaissent très souvent dans le corps des boucles. Le language Python permet de simplifier ces notations.<jupyter_code>a = 17
s = "hi"
a += 3           # Equivalent to a = a + 3
a -= 3           # Equivalent to a = a - 3
a *= 3           # Equivalent to a = a * 3
a /= 3           # Equivalent to a = a / 3
a %= 3           # Equivalent to a = a % 3
s += " there"    # Equivalent to s = s + “ there"<jupyter_output><empty_output><jupyter_text>1.2. Structures de base  ListeLes listes permettent des combinaisons de types. **Attention**, le premier élément d'une liste ou d'un tableau est indicé par **0**, pas par 1.<jupyter_code># exemples de listes
liste_A = [0,3,2,'hi']
liste_B = [0,3,2,4,5,6,1]
liste_C = [0,3,2,'hi',[1,2,3]]    
# Elément d'une liste 
liste_A[1]
liste_C[-1] #  dernier élément
liste_C[-1][0]
liste_C[-2]
liste_B[0:2] #  Sous-liste
liste_B[0:5:2]  # début:fin:pas
liste_B[::-1]
# Fonctions de listes
liste_D=[3,2,4,1]
liste_D.sort() 
print(liste_D)
liste_D.append('hi')
print(liste_D)
liste_D.count(3) 
liste_D.extend([7,8,9])
print(liste_D)
liste_D.append([10,11,12])
print(liste_D)<jupyter_output>[1, 2, 3, 4, 'hi', 7, 8, 9, [10, 11, 12]]<jupyter_text>TupleUn tuple est similaire à une liste mais ne peut être modifié, il est défini par des parenthèses.<jupyter_code>mon_tuple=(0,3,2,'h')
mon_tuple[1]
mon_tuple[1]=10 # TypeError: "tuple" object<jupyter_output><empty_output><jupyter_text>DictionnaireUn dictionnaire est similaire à une liste mais chaque entrée est assignée par une clé / un nom, il est défini avec des accolades. Cet objet est par exemple utilisé pour la construction de l'index des colonnes (variables) du type *DataFrame* de la librairie `pandas`, que l'on verra dans la suite du module.<jupyter_code>months = {'Jan':31 , 'Fev': 28, 'Mar':31}
months['Jan']
months.keys()
months.values()
months.items()<jupyter_output><empty_output><jupyter_text>2. Structures de contrôle Un bloc de commandes ou de codes est défini par *deux points suivis d'une indentation fixe*.  Cela oblige à l'écriture de codes faciles à lire mais à être très attentif sur la gestion des indentations car la fin d'indentation signifie la fin d'un bloc de commandes.  2.1 Structure itérative `for`Une boucle `for` permet, comme dans la pluspart des langages de programmation, de parcourir les éléments d'un objet *itérable*. En python cela peut-être une liste, un tuple, une chaîne de caractères (*string*), mais également des objets spécialement conçus pour cela, appelés *iterator*.Syntaxe de la structure `for`:`for` *variable* `in range` *iterator*:  &nbsp;&nbsp;&nbsp;&nbsp;    instructionLa ligne `for` se termine par deux points ':'. Le bloc de codes à l'intérieur de la boucle est *indenté*. Voici comment parcourir différentes structures itératives en se souvenant que: **de façon générale, il faut éviter les boucles `for` dans un langage interprété** en utilisant les autres fonctionnalités (section 2) prévues dans les librairies pour parcourir des tableaux ou matrices. `range`La fonction `range` produit une liste d'entiers mais aussi un objet itérable d'entiers utilisés au fur et à mesure des itérations de la boucle.**Attention** `xrange` de python2 est remplacé par `range` en python3.<jupyter_code>for i in range(5):
    print (i)<jupyter_output><empty_output><jupyter_text>L'appel à la fonction range(n) permet d'itérer sur les entiers de 0 à n-1 mais il est possible de spécifier des intervalles des valeurs de chaque pas d'itération: `range(2,11,2) range(10,0,-1)`  StringsLes chaînes de caractères sont également des objets parcourables avec la boucle `for`: caractère après caractère.<jupyter_code>for character in "Hi There!":
    print (character)<jupyter_output><empty_output><jupyter_text>DictionnairesUn dictionnaire peut être parcouru terme à terme, cependant, comme la pluspart des objets python, les dictionnaires possèdent des fonctions permettant de les transformer en une liste:    .items()    .keys()    .values()ou un *iterator*    .iteritems()    .iterkeys()    .itervalues()Les dictionnaires n'ont pas de structure ordonnée, les valeurs ne s'affichent pas forcément dans l'ordre dans lequel on les a entrées.<jupyter_code>dico={"a":1,"b":2,"c":3}
for k in dico.keys():
    print (k)<jupyter_output><empty_output><jupyter_text>Les fonctions `.items()` et `.iteritems()` permettent de parcourir les couples (clés, objets) des dictionnaires.<jupyter_code># Si une seule variable itérative est spécifiée, celle-ci est un-tuple.
for kv in dico.items():
    print (kv)
# Si deux variables itératives sont spécifiées, la première est la clé, la seconde la valeur correspondante
for k,v in dico.items():
    print (k)
    print (v)
# Si la clé ou la valeur du dictionnaire n'est pas nécessaire, elle n'est pas stockée dans une variable en utilisant "_"
for k,_ in dico.items():
    print (k)<jupyter_output><empty_output><jupyter_text>Librarie *Itertools* La librairie native de python *itertools* possède de nombreuses fonctions générant des *iterators*. Plus d'exemples dans la [documentation](https://docs.python.org/3/library/itertools.html).<jupyter_code>import itertools
#zip : Concatenne les éléments de plusieurs objets itérables
zip_list = []
for k in zip('ABCD',[1,2,3,4],"wxyz"):
    zip_list.append(k)
print("zip")
print(zip_list)
#permutation : retourne tous les arrangements possibles de liste de longueur n.
permutation_list = []
for k in itertools.permutations("ABCD",2):
    permutation_list.append(k)
print("permutations")
print(permutation_list)<jupyter_output><empty_output><jupyter_text>One-Line StatementAprès avoir parouru différents éléments d'un objet itérable et pour enregistrer un résultat pour chaque étape dans une liste, il est possible d'écrire la boucle `for` sur une seule ligne de la manière suivante:[result *for* variable in *iterator*]<jupyter_code># Version1
A1=[]
for k in range(10):
    A1.append(k*k)
    
# Version 2
A2 = [k*k for k in range(10)]
print(A1,A2)<jupyter_output><empty_output><jupyter_text>One line with for LoopDifférentes combinaisons sont possibles pour associer à la fois l'instruction `if_else` avec une boucle `for` en une ligne.<jupyter_code>#Sélectionne uniquement les valeur paire
l1 = [k for k in range(10) if k%2==0]
l1
#Retourne "even" si l'élement k est pair, "odd" sinon.
l2 = ["even" if k%2==0 else "odd" for k in range(10)]
l2<jupyter_output><empty_output><jupyter_text>2.2. Structure conditionnelle `if - else`L'instruction conditionelle `if-else` est une des plus communes en programmation informatique. En python, elle se présente sous la forme suivante:`if` *condition*: &nbsp;&nbsp;&nbsp;&nbsp;   instructions 1 `else`: &nbsp;&nbsp;&nbsp;&nbsp;   Instructions 2<jupyter_code>number=1
if number==1:
    print (True)
else:
    print (False)<jupyter_output><empty_output><jupyter_text>Lorsque plus de deux alternative sont possibles, utiliser l'instruction `elif` pour énumérer les différentes possibilités.<jupyter_code>number=13
if number<5:
    print("A")
elif number <10:
    print("B")
elif number <20:
    print("C")
else:
    print("D")
# si alors sinon
a=2
if a>0:
    b=0
    print(b)
else:
    b=-1
print(b)<jupyter_output><empty_output><jupyter_text>One-Line StatementComme pour la boucle for, il est possible d'écrire l'instruction `if_else` en une seule ligne lorsque le code est simple.<jupyter_code>number=10
"A" if number >10 else "B"<jupyter_output><empty_output><jupyter_text>2.3. Structure itérative `while`La boucle *for* permet de parcourir l'ensemble des éléments d'un objet itérable, ou un nombre déterminé d'éléments de ce dernier. Cependant, ce nombre n'est pas toujours prévisible et il est possible de parcourir ces éléments et arrêter le parcours lorsqu'une condition est respéctée ou non. C'est l'objet de l'instruction `while` avec la syntaxe:`while` *condition*: &nbsp;&nbsp;&nbsp;&nbsp;    instructionsCette instruction permet de répéter en boucle les instructions jusqu'à ce que la *condition* soit vérifiée.<jupyter_code># Incrémentation de `count` jusqu'à ce qu'elle dépasse la valeur 1.000
count = 1 
while count <= 1000: 
    count += 1 
print (count)<jupyter_output>1001<jupyter_text>L'instruction `break` permet de sortir de la boucle `while` même si sa condition est respectée.<jupyter_code>while True: 
    number = int(input("Enter the numeric grade: ")) 
    if number >= 0 and number <= 100:
        break
    else:
        print ("Error: grade must be between 100 and 0" )
    print (number)<jupyter_output>Enter the numeric grade: 2<jupyter_text>3. Fonctions<jupyter_code># Définition d'une fonction
def pythagorus(x,y):
    """ calcule l'hypoténuse d'un triangle """
    r = pow(x**2+y**2,0.5)
    return x,y,r
pythagorus(1,3)
# exemple d'appel
pythagorus(x=3,y=4)
# aide intégrée
help(pythagorus)
pythagorus.__doc__
# Définition de valeurs par défaut
def pythagorus(x=1,y=1):
    """ calcule l'hypoténuse d'un triangle """
    r = pow(x**2+y**2,0.5)
    return x,y,r
pythagorus()<jupyter_output><empty_output><jupyter_text>Références**<NAME>.** (2013). *Python for Data Analysis*, O’Reilly. [pdf](http://it-ebooks.info/book/104)**<NAME>.** (2014). *Introduction to Python for Econometrics, Statistics and Data Analysis*, [pdf](https://www.kevinsheppard.com/images/0/09/Python_introduction.pdf)**Wikistat** (2019) *La syntaxe, les objects et classes de Pyhton. Initiation au langage.* [notebook](https://github.com/wikistat/Intro-Python/blob/master/Cal1-introPython.ipynb)**Wikistat** (2019) *Programmation, classes, objets, programmation fonctionnelle.* [notebook](https://github.com/wikistat/Intro-Python/blob/master/Cal4-PythonProg.ipynb)  C - Exercices  C.1. FizzbuzzAffichez les nombre de 1 à 50, en remplaçant les multiples de 3 par fizz, les multiples de 5 par buzz, et les multiples de 15 par fizzbuzz.En sortie de cellule, vous devriez obtenir :- 1- 2- fizz- 4 - buzz- fizz- 7- 8- fizz- buzz- 11- fizz- 13- 14- fizzbuzz- 16- etc.>**Aide** : ``a % b``rend la valeur de a modulo b. Si a est multiple de 3, a % 3  vaut 0.*Note : Cet exercice est parfois utilisé en test technique  de pré-embauche.*<jupyter_code>for i in range(1, 51):
    if i % 15 == 0:
        print("fizzbuzz")
    elif i % 3 == 0:
        print("fizz")
    elif i % 5 == 0:
        print("buzz")
    else:
        print(i)<jupyter_output>1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz
fizz
22
23
fizz
buzz
26
fizz
28
29
fizzbuzz
31
32
fizz
34
buzz
fizz
37
38
fizz
buzz
41
fizz
43
44
fizzbuzz
46
47
fizz
49
buzz<jupyter_text>Pour les one-liners fous :)<jupyter_code>['fizz'*(i%3==0)+'buzz'*(i%5==0)+str(i)*(i%3!=0 and i%5!=0) for i in range(1,51,1)]<jupyter_output><empty_output><jupyter_text>C.2. Tri à bullesDéfinissez la fonction ``swap``, qui prend en entrée une liste, et deux entiers, puuis intervertit les deux élements de cette liste indexés par ces entiers.Puis, implémentez une fonction prenant en entrée une liste, et retournant en sortie cette liste triée. Utilisez un tri à bulle !Vous pourrez le tester sur une liste désordonnée.> **Aide** : Le pseudo-code de l'algorithme du tri à bulles>``procedure bubbleSort(A : list of sortable items)    n := length(A)    repeat        newn := 0        for i := 1 to n - 1 inclusive do            if A[i - 1] > A[i] then                swap(A, i-1, i)                newn := i            end if        end for        n := newn    until n ≥ 1end procedure``**Réf** : https://en.wikipedia.org/wiki/Bubble_sort*Note : cet exercice sert de prétexte pour vous faire manier les boucles et les listes*<jupyter_code>def swap(A, i, j):
    """ intervertit les indices i et j de la liste A """
    inter = A[i]
    A[i] = A[j]
    A[j] = inter

def bubbleSort(A):
    """ Applique un tri à bulle sur la liste A, et la renvoie """
    n = len(A)
    while n > 0:
        newn = 0
        for i in range(1, n):
            if A[i - 1] > A[i]:
                swap(A, i-1, i)
                newn = i
        n = newn
    return A

bubbleSort([2,90,58, 6, 35, 64, 1, 85, 6])<jupyter_output><empty_output><jupyter_text>C.3. FibonacciImplémentez une fonction ``fibo`` rendant le terme d'ordre n de la suite de Fibonacci, définie par :- $u_{0}=0$, $u_{1}=1$- $\forall n \ge 0, u_{n+2}=u_{n+1}+u_{n}$Affichez les 30 premiers termes de la suite de Fibonacci.>**Aide** : Vous pouvez réutiliser la fonction récursivement*Note : cet exercice sert de prétexte pour vous faire manier les fonctions et la récursivité*<jupyter_code>def fibo(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fibo(n-1)+fibo(n-2)

for i in range(30):
    print(fibo(i))<jupyter_output>0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229<jupyter_text>C.4. FactorielleImplémentez une fonction ``facto`` rendant n factorielle (notée $n!$), avec- $0!=1$- $\forall n \ge 0, (n+1)!=(n+1)*n! = (n+1)*n*...*2*1$De deux manières différentes:- Une itérative, avec une boucle ``for``- Une récursive, en appelant la fonction au terme d'avant>**Aide** : Vous pouvez réutiliser la fonction récursivement*Note : cet exercice sert de prétexte pour vous faire manier les boucles, les fonctions et la récursivité*<jupyter_code>def facto(n):
    if n == 0:
        return 1
    else:
        return n*facto(n-1)

print(facto(14))

def facto(n):
    res = 1
    for i in range(1, n+1):
        res*=i
    return res

print(facto(14))<jupyter_output>87178291200
87178291200<jupyter_text>C.5. Prédire les sorties de programmesEssayez de prédire ce que vont afficher ces programmes, puis exécutez le code pour vérifier.Indiquez quelles sont les valeurs imprimées en sorties.Si vous ne comprenez pas une sortie de code, appelez-moi!*Note : cet exercice permet d'améliorer votre lecture du code***Réf** : Cet exercice est tiré du TD de Lucas Bourneuf.  C.5.A<jupyter_code>a , b , c = 10 , 5 , 1
a + b # 15, mais ne change pas la valeur de a et b
a - c # 9, mais ne change pas la valeur de a et c
print ( a , b , c )
a += b # a <- 15
b = a - b # b <- 15-5 = 10
a -= b # a <- 15-10 = 5
print ( a , b , c )<jupyter_output>10 5 1
5 10 1<jupyter_text>C.5.B<jupyter_code>a , b , c = True , False , True
if a and b : # a est vrai mais b est faux, on ne rentre pas dans le bloc
    if c or a :
        print(1)
    elif c :
        print(2)
    elif c or c :
        print(3)
    else :
        print(4)
if (a or b) and (b or c) : 
    # (a ou b) est vrai car a est vrai, (b ou c) est vrai car c est vrai,
    #  (a ou b) et (b ou c) est donc vrai, on rentre dans ce bloc d'instructions
    if b:
        # b est faux, on ne rentre pas
        print(5)
    elif a:
        # a est vrai, donc on affiche 6
        print(6)
else :
    print(7)<jupyter_output>6<jupyter_text>C.5.C<jupyter_code>a = 10
while a > 0.5: # jusqu'à ce que a soit inférieur (ou égal) à 0.5
    a -= 2 # on enlève 2 à a
    print(a) # on affiche a 
    a -= 1 # on décrémente a<jupyter_output>8
5
2
-1<jupyter_text>C.5.D<jupyter_code>p , q = 10 , 20
while p : # tant que p n'est pas égal à 0
    p -= 1 # on décrémente p
    q -= -1 # on enlève -1, donc on ajoute 1 à q 
print(q) # q = 20+valeur initiale de p = 20+10 = 30<jupyter_output>30<jupyter_text>C.5.E<jupyter_code>a = 10
while a != 0:
    a -= 1 # on décrémente a
    a == 0 # cette ligne ne sert pas, c'est un boléen valant vrai si a vaut 0
    print(a)
print(a)<jupyter_output>9
8
7
6
5
4
3
2
1
0
0<jupyter_text>C.5.F<jupyter_code>l = [1 , 2 , 3 , 4 , 5]
for e in l: # pour chaque élément de l
    print( e , l )
    if e%2: # si e est impair, e%2 vaut 1, donc vrai
        print(e*2) # on affiche deux fois la valeur de e
    elif not e or e : 
        # sinon, soit si e ou non e (tautologie), donc dans tous les cas, on affiche la valeur du carré de e
        print(e**2)<jupyter_output>1 [1, 2, 3, 4, 5]
2
2 [1, 2, 3, 4, 5]
4
3 [1, 2, 3, 4, 5]
6
4 [1, 2, 3, 4, 5]
16
5 [1, 2, 3, 4, 5]
10<jupyter_text>C.5.G<jupyter_code>a = 0
a += 1 # a vaut 1
b = a + 1 # b vaut 2
print ( a + b ) # a+b vaut 3<jupyter_output>3<jupyter_text>C.5.H<jupyter_code>a , b , c = [ None ] * 3 # une manière d'affecter None à a, b et c
print( a , b , c )<jupyter_output>None None None<jupyter_text>C.5.I<jupyter_code>def inkspot(n):
    return ("I don ’ t want to set the "
            + str(n) + " in fire")
words = ('banana', 'cthulhu', 'world')
for word in words : # pour chaque mot du tuple
    print (inkspot(word)) # on insère le mot dans la phrase et l'affiche<jupyter_output>I don ’ t want to set the banana in fire
I don ’ t want to set the cthulhu in fire
I don ’ t want to set the world in fire<jupyter_text>C.5.J<jupyter_code>p , q , r = True , False , None
# p et r vaut None
# q et r est faux
print(any(( p and q , p or q , p or r ))) 
# any = ou généralisé, au moins une condition doit être vraie pour que l'ensemble soit vrai
# p et q est faux car q est faux
# p ou q est vrai car p est vrai
# p or r est vrai car p est vrai
# c'est vrai car p ou q est vrai
print(all(( p or q , p or r , r or q ))) 
# all = et généralisé, toutes les conditions doivent être vérifiées
# r ou q vaut None
# c'est faux<jupyter_output>True
False<jupyter_text>C.5.K<jupyter_code>print(len({'a': 'bb', 'bb': 'cc'}['a']))
# on appelle la valeur associée à la clef 'a' du dictionnaire
# ce n'est pas la longueur du dictionaire,
# mais bien celle de la chaine de caractères 'bb' qui est renvoyée, donc 2<jupyter_output>2<jupyter_text>C.5.L<jupyter_code>a = [3 , 2 , 1]
print(a.pop() + a.pop() * a.pop()) # le premier vaut 1, le second vaut 2, le troisième 3, donc 1+2*3=7<jupyter_output>7<jupyter_text>C.5.M<jupyter_code>ps = [i % 2 for i in range ( 0 , 20 , 4 )]
print(True and 'all(p == 0 for p in ps)')<jupyter_output>all(p == 0 for p in ps)<jupyter_text>C.5.N<jupyter_code>if (i for i in range(2)): 
    print (1)
if any(i for i in range(2)): 
    print (2)
if all(i for i in range(2)): 
    print (3)<jupyter_output>1
2<jupyter_text>C.5.O<jupyter_code>def f(n) :
    print(n)
    return n
print(f(1), f(2), f(3))<jupyter_output>1
2
3
1 2 3<jupyter_text>C.5.P<jupyter_code>a = [1]
b = a
b.append(2)
print(a, b)<jupyter_output>[1, 2] [1, 2]<jupyter_text>C.5.Q<jupyter_code>def f(l = []) :
    l.append(1)
    return l
print(f(f()), f())<jupyter_output>[1, 1, 1] [1, 1, 1]<jupyter_text>Le piège de cette question est lié au fait que python garde en mémoire les arguments par défaut.Au premier appel de la fonction f sans argument, la valeur de l est initialisée à la liste vide. Puis on ajoute l'élément 1 à la liste.Au second appel de la fonction f, la fonction va chercher l'argument par défaut. Et comme elle l'a déjà en mémoire, elle prend la variable par défaut l modifiée la fois d'avant, donc [1] et non pas []. Donc on rajoute 1, à la liste [1], l'argument par défaut devient [1,1]. En résumé, chaque appel de f ajoute un élément 1 à l, et f() renvoie une liste de 1 de longueur égale au nombre de fois où f a été appelée.Le problème n'en est plus un si l'élément par défaut est immutable : si on ne peut pas le changer, la valeur par défaut restera tout le temps la même.Pour explication plus détaillée, vous pouvez consulter cet article:https://florimond.dev/blog/articles/2018/08/python-mutable-defaults-are-the-source-of-all-evil/  C.5.R<jupyter_code>a, b, c = [1, 2, 3]
print(a, b, c, sep= '#', end= '4\n')<jupyter_output>1#2#34<jupyter_text>C.5.S<jupyter_code>b = set()
for i in range(15):
    if i%2==0:
        b.add(i)
print(len(b))<jupyter_output>8<jupyter_text>C.6. Comprendre les erreurs pythonNe plus avoir peur des erreurs : indiquer quelle erreur est levée, ce qu’elle signifie, quelle instruction l’a causée et pourquoi, et proposer une correction qui préserve le comportement du programme.*Note : cet exercice vous permet d'améliorer votre capacité à corriger le code***Réf** : Cet exercice est tiré du TD de Lucas Bourneuf.<jupyter_code>%reset<jupyter_output>Once deleted, variables cannot be recovered. Proceed (y/[n])? y<jupyter_text>C.6.A<jupyter_code>a = b<jupyter_output><empty_output><jupyter_text>Ici, ``b`` n'est pas reconnue comme étant une variable définie et utilisable. On peut par exemple affecter une valeur à ``b`` dans un premier temps, puis affecter à ``a`` la valeur de ``b``.<jupyter_code>b = 2
a = b<jupyter_output><empty_output><jupyter_text>C.6.B<jupyter_code>if 10 = 8 :
    10 + 8<jupyter_output><empty_output><jupyter_text>Sur cette question, la condition ne contient pas un booléen, ayant la valeur de vérité vrai ou faux, ce qui renvoie une erreur de syntaxe après une condition ``if``.- ``a = b`` est une affectation de la valeur de ``b`` dans la variable ``a``- ``a == b`` est un booléen valant vrai si la valeur de ``a`` vaut celle de ``b``On peut par exemple remplacer ``10 = 8`` par ``10 == 8``. Le code suvant est sytaxiquement correct, et ne lève pas d'erreur:<jupyter_code>if 10 == 8:
    10+8<jupyter_output><empty_output><jupyter_text>En revanche, il ne fait rien d'utile!  C.6.C<jupyter_code>2*(3-4<jupyter_output><empty_output><jupyter_text>Sur cette question, l'opérateur ``*`` attend un entier, ou une variable en général, qu'il puisse multiplier par 2. Ici, la parenthèse ouverte n'a pas été refermée, ce qui empêche l'évaluation de ``3-4``. Le code suivant fonctionne :<jupyter_code>2*(3-4)<jupyter_output><empty_output><jupyter_text>C.6.D<jupyter_code>msc = { 'f' :
msc['t']<jupyter_output><empty_output><jupyter_text>Sur cette question, même type d'erreur que sur la question précédente; l'accolade ouvrante n'est pas fermée, et le dictionnaire msc n'a pas de valeur associé à la clé 'f'. Dans un premier temps, on complète le dictionnaire.<jupyter_code>msc = { 'f' : 2 }
msc['t']<jupyter_output><empty_output><jupyter_text>Encore une erreur ! Mais cette fois, pas de problème de syntaxe. L'erreur est levée car le dictionnaire ne contient pas la clé 't'. Cette solution devrait marcher:<jupyter_code>msc = { 'f' : 2, 't' : 3}
msc['t']<jupyter_output><empty_output><jupyter_text>C.6.E<jupyter_code>msc = { ’ f ’ :
{msc : 19}<jupyter_output><empty_output><jupyter_text>Le même type d'erreur qu'en ``C.6.D``. Tout d'abord, on corrige l'erreur comme sur la question précédente.<jupyter_code>msc = { 'f' : 2, 't' : 3}
{msc : 19}<jupyter_output><empty_output><jupyter_text>Ici, on essaie d'utiliser un dictionnaire comme clef d'un second dictionnaire.D'un point de vue lecture de code, c'est déjà une mauvaise idée, donc ne faites pas ça chez vous!Ça ne fonctionne pas, comme l'explique très bien cette réponse sur stackoverflow : https://stackoverflow.com/questions/13264511/typeerror-unhashable-type-dictJe propose de s'en tenir à cette ligne de code pour le ``C.6.E``!<jupyter_code>msc = { 'f' : 2, 't' : 3}<jupyter_output><empty_output><jupyter_text>C.6.F<jupyter_code>if True :
    pass
pass
else :
    pass<jupyter_output><empty_output><jupyter_text>L'instruction ``pass`` permet d'ignorer le fait que le contenu d'une boucle est vide, et de sortir d'une boucle sans lever d'erreur, comme par exemple pour cette cellule de code.<jupyter_code>if b == 3:
    
if b == 3:
    pass<jupyter_output><empty_output><jupyter_text>Ici, le problème vient du second ``pass``, qui casse la structure ``if-else``. Comme un ``else`` seul lève une erreur, le code ne marche pas. Cette solution résoud l'erreur:<jupyter_code>if True :
    pass
else :
    pass<jupyter_output><empty_output><jupyter_text>C.6.G<jupyter_code>(3)[0]<jupyter_output><>:1: SyntaxWarning: 'int' object is not subscriptable; perhaps you missed a comma?
<>:1: SyntaxWarning: 'int' object is not subscriptable; perhaps you missed a comma?
<ipython-input-79-bb9e3b0941a9>:1: SyntaxWarning: 'int' object is not subscriptable; perhaps you missed a comma?
  (3)[0]<jupyter_text>Ici, ``(3)`` est considéré comme un entier<jupyter_code>type((3))<jupyter_output><empty_output><jupyter_text>On peut imaginer que la personne qui a codé cette instruction voulait définir un tuple, et accéder au premier élément. Deux solutions sont envisageables:- Solution 1<jupyter_code>(3, 2)[0]<jupyter_output><empty_output><jupyter_text>On rajoute un élément, et python comprend que l'on souhaite définir un tuple. Par la suite, on peut facilement accéder au terme 0 de ce tuple.<jupyter_code>type((3,2))<jupyter_output><empty_output><jupyter_text>- Solution 2 : on renvoie juste l'entier<jupyter_code>(3)<jupyter_output><empty_output><jupyter_text>C.6.H<jupyter_code>sum( 1 , 2 , 3 , 4 )<jupyter_output><empty_output><jupyter_text>Ici, le codeur a probablement voulu faire la somme des entiers 1,2,3,4. Le problème est bien expliqué par l'erreur : la fonction ``sum()`` ne prend en paramètres que deux arguments au maximum, alors que 4 arguments sont donnés. Voici une solution utilisant une liste, et la fonction ``sum()`` associée aux listes:<jupyter_code>sum([1,2,3,4])<jupyter_output><empty_output><jupyter_text>C.6.I<jupyter_code>if 9 in 899:
    pass<jupyter_output><empty_output><jupyter_text>On retrouve une erreur similaire à celle levée par ``C.6.G``. Voici une proposition de solution:<jupyter_code>if 9 in [9, 899]:
    pass<jupyter_output><empty_output><jupyter_text>C.6.J<jupyter_code>''.join((1 , 2))<jupyter_output><empty_output><jupyter_text>Dans cette question, on essaie d'ajouter deux entiers à une chaine de caractère. De manière générale, il faudra toujours convertir les entiers ``int`` en string ``str`` pour les ajouter.Deux solutions pour forcer la classe str :- Avec la fonction str()<jupyter_code>''.join((str(1) , str(2)))<jupyter_output><empty_output><jupyter_text>- en rajoutant des '' à la main, ce qui revient au même<jupyter_code>''.join(('1' , '2'))<jupyter_output><empty_output><jupyter_text>C.6.K<jupyter_code>10 + '10'<jupyter_output><empty_output><jupyter_text>Ici, on essaie d'appliquer l'opérateur + à un entier et un caractère (texte). On peut soit changer le caractère en entier, et dans ce cas on fait juste une addition:<jupyter_code>10+int('10')<jupyter_output><empty_output><jupyter_text>Soit changer l'entier en texte, et dans ce cas on concatène les deux chaines de caractères:<jupyter_code>str(10)+'10'<jupyter_output><empty_output><jupyter_text>C.6.L<jupyter_code>if 'hal' = 'ibm':
    print('kbk')<jupyter_output><empty_output><jupyter_text>Même erreur qu'en ``C.6.B``, pour de la comparaison de chaine de caractère. Voici une proposition de solution:<jupyter_code>if 'hal' == 'ibm':
    print('kbk')<jupyter_output><empty_output><jupyter_text>C.6.M<jupyter_code>scores = { 'diphonic' : 10 , 'yoddle' : 8.45 }
print(sum(scores.values()), scores['grunt'])<jupyter_output><empty_output><jupyter_text>Ici, même erreur que la deuxième partie de ``C.6.D``, la clé n'est pas dans le dictionnaire.Proposition :<jupyter_code>scores = { 'diphonic' : 10 , 'yoddle' : 8.45 }
print(sum(scores.values()), scores['yoddle'])<jupyter_output>18.45 8.45<jupyter_text>C.6.N<jupyter_code>nbuser = input("Gimme an integer before midnight : ")
print(10+nbuser)<jupyter_output>Gimme an integer before midnight :<jupyter_text>``input()`` permet à l'utilisateur de spécifier une valeur en l'écrivant dans un champ texte. Mais ici, il faut s'assurer que la variable ``nbuser`` est bien un entier en forçant le type.<jupyter_code>nbuser = input("Gimme an integer before midnight : ")
print(10+int(nbuser))<jupyter_output>Gimme an integer before midnight : 1
11<jupyter_text>C.6.O<jupyter_code>d = {}
for idx in range(0, 10, 3) :
    d[idx] = idx**5
d[6]
d[2]
d[10]<jupyter_output><empty_output><jupyter_text>Une erreur de clé. La boucle ``for`` a un pas de 3, ce qui invalident les appels aux clés non multiples de 3, et sa valeur max est 10, qui n'est pas inclus dans l'ensemble des valeurs parcourues.<jupyter_code>d = {}
for idx in range(0, 11, 1) :
    d[idx] = idx**5
d[6]
d[2]
d[10]<jupyter_output><empty_output><jupyter_text>C.6.P<jupyter_code>elif True :
    pass<jupyter_output><empty_output><jupyter_text>L'instruction ``elif`` suit toujours une condition ``if``.Proposition :<jupyter_code>if a ==2:
    pass
elif True:
    pass<jupyter_output><empty_output><jupyter_text>C.6.Q<jupyter_code>print(f, u, n, k, y)<jupyter_output><empty_output><jupyter_text>Les variables ne sont pas définies!<jupyter_code>f = 'you'
u = 'pi,'
n = 'you'
k = 'pi,'
y = 'yeah!'
print(f, u, n, k, y)<jupyter_output>you pi, you pi, yeah!<jupyter_text>C.6.R<jupyter_code>d = int(input('str'))
str(d)*4+d<jupyter_output>str<jupyter_text>Cette instruction n'est vraiment pas claire! On ne comprend pas l'intention du développeur.On demande d'abord à l'utilisateur du texte, converti en entier... Puis on essaie d'ajouter quatre fois l'input de l'utilisateur converti en texte à l'input entier...Superbe contre-exemple, à ne surtout pas reproduire!!!On tente quand même une correction?<jupyter_code>d = int(input('Entier'))
str(d)*4+str(d)<jupyter_output>Entier2<jupyter_text>C.7. Codage de CésarDéfinissez un dictionnaire ``nums`` associant à chaque lettre son numéro d'apparition dans l'alphabet.On associera 0 au caractère espace.Par exemple, la lettre 'a' (clef) du dictionnaire sera associée au chiffre 1 (valeur), 'b' à 2, 'c' à 3, etc.Implémentez une fonction ``code`` prenant en entrée une chaine de caractères (supposée en minuscule) et un entier p, remplaçant chaque caractère par la lettre située p emplacements après dans l'alphabet.>**Aide** : si la lettre considérée est Z et que p vaut 2, la lettre doit être remplacée par A (car 0 est associé à l'espace). Si n est le numéro de la lettre courante, le numéro de la lettre de remplacement vaut (n + p)% 27Affichez le codage de César (p=5) de cette phrase : "trop faciles ces exercices"Je sais que le codage de César a été utilisé pour coder la phrase decodez_moi, mais je ne connais pas la clef p utilisée. Peux-tu m'aider à retrouver sa signification?*Note : cet exercice sert de prétexte pour vous faire manipuler les dictionnaires*<jupyter_code>alphabet = (" ", 
            "a","b","c","d","e","f","g","h","i","j","k","l","m",
            "n","o","p","q","r","s","t","u","v","w","x","y","z")
decodez_moi = "mntiynqtiullyktuteutlnbmy"
nums = dict()

for l in range(len(alphabet)):
    nums[alphabet[l]] = l

nums
def cesar(msg, p):
    """ code la chaine de caractère suivant le codage de César avec la clef p """
    
    msg_code = ""
    # le futur message codé
    
    for i in range(len(msg)):
        m = msg[i] # la lettre courante
        n = (nums[m]+p)%27 # le numéro à remplacer
        msg_code+= [k for (k, v) in nums.items() if v == n][0] # le premier élement qui correspond au bon numéro
    return msg_code

cesar("trop faciles ces exercices", 5)
for p in range(27):
    print(cesar(decodez_moi, p))<jupyter_output>mntiynqtiullyktuteutlnbmy
noujzorujvmmzluvufvumocnz
opvk psvkwnn mvwvgwvnpdo 
pqwlaqtwlxooanwxwhxwoqepa
qrxmbruxmyppboxyxiyxprfqb
rsyncsvynzqqcpyzyjzyqsgrc
stzodtwzo rrdqz zk zrthsd
tu peux passer a la suite
uvaqfvyaqbttfsabambatvjuf
vwbrgwzbrcuugtbcbncbuwkvg
wxcshx csdvvhucdcodcvxlwh
xydtiyadtewwivdedpedwymxi
yzeujzbeufxxjwefeqfexznyj
z fvk cfvgyykxfgfrgfy ozk
 agwladgwhzzlyghgshgzap l
abhxmbehxi  mzhihtih bqam
bciyncfiyjaan ijiujiacrbn
cdjzodgjzkbboajkjvkjbdsco
dek pehk lccpbklkwlkcetdp
eflaqfilamddqclmlxmldfueq
fgmbrgjmbneerdmnmynmegvfr
ghncshkncoffsenonzonfhwgs
hiodtilodpggtfopo pogixht
ijpeujmpeqhhugpqpaqphjyiu
jkqfvknqfriivhqrqbrqikzjv
klrgwlorgsjjwirsrcsrjl kw
lmshxmpshtkkxjstsdtskmalx
StarcoderdataJupyterStructuredCleanDedup