#!/usr/bin/env python # coding: utf-8 # Open In Colab # # Python : Révision des outils de base grâce à Jupyter notebook # # # # Ce notebook est proposé dans le cadre d'une préparation au **Cours de mathématiques & informatique** en B.C.P.S.T.2 - Externat des enfants nantais proposé par [J. Laurentin](). # ## Opération préliminaire. # # **Une fois connecté** (sur le bandeau, en haut à droite) commencer par enregistrer une copie de ce notebook dans votre **Drive** ("Fichier" + "Enregistrer une copie dans Drive...""). C'est sur **CETTE** copie que je vous suggère de travailler par la suite si vous voulez conserver vos modifications. # # Une fois cette opération réalisée, vous pourrez par la suite accéder directement à vos notebooks depuis "colab.research.google.com" (téléphone ou ordinateur). # Il suffira d'aller dans l'onglet "Fichier" puis "ouvrir un notebook", pous accéder à l'ensemble des notebooks enregistrés dans **votre Drive** mais aussi les fichiers source placés sur Github. # # Je vous souhaite de prendre beaucoup de plaisir grâce à ces outils de révision ! # ## 1. Prise en main # Le Notebook d'IPython est un environnement intéractif pour écrire et faire tourner du code Python. # Il se présente sous la forme d'une succession de cellules qui contiennent soit un texte d'explication ou un code exécutable et sa sortie. Il suffit de cliquer sur une cellule pour la sélectionner. # Les cellules de code sont facilement identifiable car précédées d'un `[]`. # Ci-dessous une cellule de code. # Pour **exécuter le code** Python de cette cellule, il vous faut, au choix, taper : # # 1. Cliquer sur le bouton "lecture" au début de la cellule sélectionnée. # 2. Faire `ctrl + Enter` pour exécuter la cellule en place. # 3. Faire `maj + Enter` pour exécuter la cellule et aller à la cellule suivante. # 4. Faire `alt + Enter` pour exécuter la cellule et insérer une cellule de code immédiatement après. # # # Il suffit d'essayer... # In[ ]: a,b = 2,3 print('a*b vaut',a*b) # Il est toujours possible d'effacer l'élément de sortie en se plaçant sur la cellule et de cliquer sur la `croix`. # Mais c'est le plus souvent inutile car il est possible de relancer une ligne autant de fois qu'on le souhaite après l'avoir modifiée. # Par exemple, modifiez les lignes de code `[1]` pour initialiser la variable `b` à 5 et afficher la valeur de `a+b`. # vous devriez voir afficher 'a+b vaut 7'. # D'un point de vue pratique, on notera que toutes les fonctionnalités d'Ipython sont ici opérationnelles. # On travaille de façon privilégiée avec les listes, mais il est utile d'importer certaines bibliothèques pour faire certains calculs d'analyse, d'algèbre, de probabilité ou encore proposer des représentations graphiques. # Ainsi, exécutez la ligne suivante sans importer de bibliothèque : # In[ ]: y = exp(a) # Un message d'erreur apparaît qui précise que cette fonction "exp" n'est pas définie... # Il suffit d'importer la bibliothèque `math` pour lever ce problème. # Ainsi : # In[ ]: from math import * # On peut désormais faire : # In[ ]: x = 2 y = exp(x)-1 print(x,'|',y) # In[ ]: print(e,'|',log(e)) # On importera également la bibliothèque `numpy` comme à l'accoutumée # In[ ]: import numpy as np # On peut désormais créer un tableau t1 de réels compris entre `0` et `1` par pas de `0.1` # In[ ]: t1 = np.arange(0,1.1,0.1) print(t1) # ou encore créer un tableau `t2` de 10 réels compris entre `0` et `1` (compris). # In[ ]: t2 = np.linspace(0,1,10) print(t2) # Il est aussi possible d'écrire des fonctions plus complexes. # Par exemple pour la suite de Fibonacci définie par $u_0=1=u_1$ et $u_{n+2}=u_{n+1}+u_n$, $\forall n\geq 0$ # on calculera et on affichera ses dix premiers termes en écrivant : # In[ ]: a,b=1,1 # initialisation de deux premiers termes print(a,b,end = " ") n=1 while n<11 : a,b = b,a+b print(b,end = " ") n = n+1 # **Attention** Vous noterez que tous les termes de la suite ont été affichés sur une seule ligne. # Ce résultat est obtenu grâce à l'argument `end = " "` fourni à la fonction `print()`. # Supprimez cet argument et vérifiez que les termes sont affichés les uns en dessous des autres. # ## 2. Quelques éléments sur Python, langage *Orienté Objet* # Avec Python, tout est objet : données, fonctions, modules... # > Un **objet** : # - possède une *identité* (à savoir une adresse mémoire); # - possède un *type* : un objet est l’instanciation d’une classe qui définit son type # (par exemple : int, float, str); # - contient des *données* (par exemple, si c'est un objet numérique, cette donnée est sa *valeur*). # # > Un objet est référencé par un **identificateur** : # - on trouvera également "référence", "nom", "étiquette", comme synonymes d'indentificateur; # In[ ]: a = 5 # a est l'identificateur et 5 est une expression évaluée comme objet. # In[ ]: # il est possible d'afficher l'identité et le type de l'objet référencé : print(id(a)) # identité print(type(a)) # type # In[ ]: b = a # deuxième nom (étiquette ou référence) pour l'entier 5 print(id(b)) print(type(b)) # In[ ]: c = 5.0 # nouvel identificateur qui pointe cette fois vers 5.0 # In[ ]: type(c) # In[ ]: print(id(a),id(b),id(c)) # In[ ]: a == b # égalité des valeurs des deux objets # In[ ]: a == c # égalité des valeurs # In[ ]: a is c # test l'égalité des identités # In[ ]: a is b # test l'égalité des identités # On retiendra que a, b et c ont même valeur mais que c se distingue de a et b car son identité et son type son distincts. # **Attention !** Tous les objets ne sont pas modifiables ! # > Un objet dont le contenu peut être changé est dit **mutable** (non mutable dans le cas contraire). # A titre d'exemple une chaîne de caractère est un objet non mutable tandis qu'une liste est un objet mutable. # In[ ]: T = 'Feci est un texte non modifiable' print(T) # In[ ]: T[0]='C' # In[ ]: L = [12,-5.0,'oups'];L # In[ ]: L[2]=3;L # In[ ]: print(L) # **Remarque importante** sur les copies d'objets qui peuvent donner lieu à des erreurs difficiles à déceler : # In[ ]: M = L print(M) # In[ ]: M[1]=60 # modification de la liste M print(M) # La question est de savoir si la liste `L` aussi a été modifiée... # In[ ]: L # In[ ]: L is M # L et M ont la même identité. Ils pointent vers le même objet et il est normal que L soit modifiée également. # Il existe deux solutions pour faire la copie d'un objet : La copie *superficielle* ou la copie *profonde*. # Nous verrons ça à la fin du paragraphe 3.2 *Modification d'une liste* # ## 3. Manipulation des listes : # Les **listes** représentent un type de données composées extrêment utiles sous Python. # On peut les voir comme une *collection d'éléments séparés par des virgules, l'ensemble étant enfermé dans des crochets*. # Les éléments peuvent être de type très différents. Par exemple : # In[ ]: L1 = [1,2,3.5,'7',-2.4,'test'] # In[ ]: print(L1) # ### 3.1 Accès aux éléments d'une liste : # Il est possible d'accéder à n'importe quel élément d'une liste en indiquant entre crochets l'index numérique qui correspond à la position de l'élément. # In[ ]: # Obtenir un élément de la liste : print('le 3ème éléments vaut : ',L1[2]) print('le dernier élément vaut : ',L1[-1]) # # Essayez successivement dans la ligne ci-dessous : `L1[0]`, `L1[5]`, `L1[-1]`, `L1[-1][1]` # In[ ]: # On obtient la **longueur** d'une liste ou d'une chaîne en faisant appel à la fonction `len()` : # In[ ]: n1 = len(L1) print('la longueur de L1 vaut : ',n1) print('la longueur de la chaîne de caractère "test" vaut : ',len(L1[-1])) # Il est aussi possible de savoir si un élément est dans une liste : # In[ ]: 3 in L1 # In[ ]: u = 3.5 if u in L1: print(u,' est dans L1') # #### On notera qu'une liste peut donc est formée de plusieurs types d'éléments. # 1. Les **type integer** (par exemple `L1[0]` et `L1[1]` sont des entiers). # 2. Les **type float** pour *floating point number* (`L1[2]` est un "nombre réel" ou "nombre à virgule flottante). # 3. Les **type string** (`L1[3]` et `L1[5]` sont des chaînes de caractères). # # On obiendra le type d'un élement en faisant appel à la fonction `type()`. # Par exemple on essaira ci-dessous `type(L1)`, `type(L1[0])`, `type(L1[2])` ou encore `type(L1[3])` : # In[ ]: type(L1) # *Remarque :* Dans le cas de `L1[3]` on vérifiera qu'il s'agit bien d'un caractère et non d'un entier ! # # Cela étant, il est possible d'accéder à bien mieux qu'à un seul élément d'une liste. # Il est en effet possible d'extraire n'importe quelle sous-liste et ce dans l'ordre de votre choix. # Commençons par extraire les trois premiers éléments de `L1` : # In[ ]: print(L1[0:3]) print(L1[:3]) # In[ ]: print('L1 vaut : ',L1) print(L1[1:]) print(L1[1:-1]) print(L1[1:4:2]) # index de 1 à 4 (exclus) par pas de 2. print(L1[4:1:-1]) # index de 4 à 1 (exclus) par pas de -1. print(L1[::-1]) # Affichage inversé de tout L1. # A vous de jouer en créant à la suite de ce texte une nouvelle ligne de code (cliquer sur le symbole '+ Code' dans la zone intercellule ou utiliser l'onglet "insérer") au sein de laquelle vous initialisez une liste `L2` de votre choix et en s'entraînant à accéder à n'importe laquelle des sous-listes possibles. # # **Attention** : Respecter l'affectation de ce nom (`L2`) à la liste que vous allez créer, sans quoi les indications du paragraphe 3.2 ne coincideront plus avec la liste `L1` sur laquelle nous continuons de travailler ! # Souvenez-vous qu'il est toujours possible de supprimer une ou des cellules qui ont été créées en utilisant 'Modifier' ou bien les "trois petits points situés en fin de cellule". # Il est aussi possible de réinitialiser l'ensemble des cellules, en allant dans l'onglet 'Exécution' et en exécutant 'Réinitialiser tous les environnements d'exécution...''. # In[ ]: L2 = ... # A compléter # ### 3.2. Modification d'une liste : # Nous rappelons que les listes sont des objets *mutables*. # Si on connaît l'index d'un élément, il est facile de le changer ou de le remplacer. # Par exemple : # In[ ]: print(L1) L1[1] = L1[1]+12 print(L1) # Vous avez dû obtenir en deuxième ligne : [1, **14**, 3.5, '7', -2.4, 'test'] # Il est aussi possible de modifier le **type** des éléments de la liste grâce à des "built-in function", qu'on appellera aussi des ***méthodes*** ou *fonction primitives*. On trouvera parmis celles-ci `int()`, `float()`, `complex()`, `str()` ou encore `list()`, `set()`. # Par exemple, pour remplacer le caractère `"7"` par l'entier "7" on fera : # In[ ]: L1 = [1,14,3.5,'7',-2.4,'test'] print('L1 =',L1,'') print('L1[3] est de type :',type(L1[3])) L1[3]=int(L1[3]) # on écrira float(L1[3]) pour le transformer en type float. print(L1) print('Maintenant L1[3] est de type :',type(L1[3])) # **Exemple d'application** de ces méthodes de changement de type (d'après *Programmation en Python pour les mathématiques*, par A. Casamayou-Boucau, P. Chauvin et G. Connan, (Dunod, 2012), p.38) : # Calculer $u_n=\cfrac{C_n}{n(n+1)}$ où $C_n$ désigne le nombre de chiffres intervant dans l'écriture décimale de $n$. # In[ ]: n = 53 print('u_',str(n),' vaut :',len(str(n))/(n*(n+1))) # Plus généralement, il est particulièrement important de savoir manipuler une liste pour insérer, supprimer un élement, ou encore concaténer des listes. # Utilisez la ligne de code ci-dessous pour tester des *méthodes* particulièrement efficaces dont voici quelques exemples : # In[ ]: L1.append(14) # ajout de 14 en fin de liste print(L1) L1 = L1+[14] # autre méthode possible... print(L1) # In[ ]: L1.insert(3,54) # insertion de x=54 à la position i=3 print(L1) # In[ ]: L1.index(54) # retourne l'index de la première occurence de x=54 # In[ ]: L1.count(14) # dénombre les x=14 présents dans L1 - essayer avec d'autres valeurs... # In[ ]: del L1[6:] # suppression des termes indexés à partir de 7 print(L1) # In[ ]: L1.sort() # tri croissant de L1 print(L1) L1.sort(reverse = True) print(L1) # tri décroissant # **Attention** On rappelle que les listes sont des objets *mutables*. En particulier toute méthode appliquée à une liste ne créé pas un objet nouveau mais la modifie. Vos données d'origine sont perdues ! # Aussi, dans le cas du tri d'une liste, si on ne souhaite pas perdre la liste de départ, on préfèrera L1_triee = sorted(L1) qui fait une copie triée de L1 sans la modifier. # Voyons maintenant les moyens de faire la **copie** d'une liste - la copie *superficielle* puis la copie *profonde* : # In[ ]: L = [1,[2,3]] M = list(L) # copie superficielle: M est un nouvel objet `list` initialisé par L M[0]=10 print(L,M) M[1][0]=20 print(L,M) # Si tout se passe bien pour `M[0]`, le problème pour `M[1][0]` vient du fait que M[1] pointe vers une même liste que L[1]... aussi `L[1][0]` a-t-il aussi été modifié. # Reprenons : # In[ ]: L = [1,[2,3]] from copy import deepcopy M = deepcopy(L) # copie profonde : M est une copie complète de l'objet référencé par L M[0]=10 print(L,M) M[1][0]=20 print(L,M) # ### 3.3 Création de listes particulières : # Création d'une liste de nombres à l'aide de la fonction `range()` : # Cette fonction génère par défaut une séquence de nombres entiers de valeurs croissantes à partir de 0. # Cette séquence peut s'utiliser directement (par exemple pour une boucle `POUR`) ou bien être transformée en *liste* : # In[ ]: list(range(10)) # In[ ]: for k in range(10): print(k**2,end = " ") # Mais bien d'autres possibilités s'offrent à vous : # In[ ]: list(range(2,12)) # In[ ]: list(range(2,12,2)) # In[ ]: list(range(7,-5,-1)) # In[ ]: [0]*10 # In[ ]: [4,8,'bip']*3 # In[ ]: list(range(5))*2 # On peut aussi créer des listes "en compréhension" : # In[ ]: L = [k**2 for k in range(11)] print(L) # In[ ]: L2 = [k**2 for k in range(11) if k%2 == 0] print(L2) # ne contient que les carrés pairs puisque 'k%2' désigne le reste de la division par 2 L3 = [k**2 for k in range(11) if (k > 4) and (k%2 == 0)] print(L3) # Et même créer des listes de listes, utiles pour constituer des tableaux ou des matrices : # In[ ]: L4 = [[i**2+j for i in range(3)] for j in range(2)] print(L4) # In[ ]: print('la première ligne vaut : ',L4[0]) print('la seconde ligne vaut : ',L4[1]) print('le deuxième terme de la première ligne vaut : ',L4[0][1]) # Si on possède deux listes de même longueur, il est possible de les associer pour former des couples (appelés aussi `tupples`) : # In[ ]: Couleur = ['carreau','coeur','pique','treffle'] Hauteur = ['Roi','Dame','Valet','As'] for (c,h) in zip(Couleur,Hauteur): print(h,' de ',c) # ou encore, si on souhaite faire le produit scalaire de deux vecteurs $u$ et $v$ : # In[ ]: u = [1,0,2] v = [-1,1,3] print(sum(x*y for x,y in zip(u,v)))