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 [0]:
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 [0]:
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 [0]:
from math import *

On peut désormais faire :

In [0]:
x = 2
y = exp(x)-1
print(x,'|',y)
In [0]:
print(e,'|',log(e))

On importera également la bibliothèque numpy comme à l'accoutumée

In [0]:
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 [0]:
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 [0]:
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 [0]:
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 [0]:
a = 5 # a est l'identificateur et 5 est une expression évaluée comme objet.
In [0]:
# 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 [0]:
b = a # deuxième nom (étiquette ou référence) pour l'entier 5
print(id(b))
print(type(b))
In [0]:
c = 5.0 # nouvel identificateur qui pointe cette fois vers 5.0
In [0]:
type(c)
In [0]:
print(id(a),id(b),id(c))
In [0]:
a == b # égalité des valeurs des deux objets
In [0]:
a == c # égalité des valeurs
In [0]:
a is c # test l'égalité des identités
In [0]:
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 [0]:
T = 'Feci est un texte non modifiable'
print(T)
In [0]:
T[0]='C'
In [0]:
L = [12,-5.0,'oups'];L
In [0]:
L[2]=3;L
In [0]:
print(L)

Remarque importante sur les copies d'objets qui peuvent donner lieu à des erreurs difficiles à déceler :

In [0]:
M = L
print(M)
In [0]:
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 [0]:
L
In [0]:
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 [0]:
L1 = [1,2,3.5,'7',-2.4,'test']
In [0]:
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 [0]:
# 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 [0]:
 

On obtient la longueur d'une liste ou d'une chaîne en faisant appel à la fonction len() :

In [0]:
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 [0]:
3 in L1
In [0]:
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 [0]:
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 [0]:
print(L1[0:3])
print(L1[:3])
In [0]:
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 [0]:
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 [0]:
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 [0]:
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 [0]:
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 [0]:
L1.append(14) # ajout de 14 en fin de liste
print(L1)
L1 = L1+[14] # autre méthode possible...
print(L1)
In [0]:
L1.insert(3,54) # insertion de x=54 à la position i=3
print(L1)
In [0]:
L1.index(54) # retourne l'index de la première occurence de x=54
In [0]:
L1.count(14) # dénombre les x=14 présents dans L1 - essayer avec d'autres valeurs...
In [0]:
del L1[6:] # suppression des termes indexés à partir de 7
print(L1)
In [0]:
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 [0]:
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 [0]:
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 [0]:
list(range(10))
In [0]:
for k in range(10):
    print(k**2,end = " ")

Mais bien d'autres possibilités s'offrent à vous :

In [0]:
list(range(2,12))
In [0]:
list(range(2,12,2))
In [0]:
list(range(7,-5,-1))
In [0]:
[0]*10
In [0]:
[4,8,'bip']*3
In [0]:
list(range(5))*2

On peut aussi créer des listes "en compréhension" :

In [0]:
L = [k**2 for k in range(11)]
print(L)
In [0]:
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 [0]:
L4 = [[i**2+j for i in range(3)] for j in range(2)]
print(L4)
In [0]:
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 [0]:
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 [0]:
u = [1,0,2]
v = [-1,1,3]
print(sum(x*y for x,y in zip(u,v)))