Python pour le calcul scientifique/Découverte de Python et de Jupyter
Python est un langage interprété. Il peut s'utiliser en ligne de commande, l'invite étant représentée par trois chevrons
>>> 3+2
5
Le code source peut être mis dans un fichier texte portant l'extension de nom de fichier .py. Cela requiert donc un éditeur de texte.
Les fichiers que nous allons créer commenceront tous de la manière suivante :
#!/usr/bin/python3
import numpy as np
import matplotlib.pyplot as plt
La première ligne, appelée shebang, n'est pas utile avec l'environnement que nous allons utiliser mais il est intéressant de la mettre pour assurer une compatibilité du code avec d'autres environnements. Les lignes commençant par import permettent d'importer des bibliothèques de fonctions ; nous en ajouterons au gré des besoins.
Nous allons utiliser l'environnement de programmation Jupyter, un environnement libre, gratuit et multiplateforme. Jupyter utilise un navigateur Internet comme éditeur de texte et pour l'affichage des résultats.
Installer Jupyter
[modifier | modifier le wikicode]
Nous utilisons la distribution Anaconda : https://www.anaconda.com/
Suivez les instructions d'installation selon votre système. Choisissez « Python 3 ».
/anaconda3/bin/jupyter-lab.Bien entendu, vous pouvez aussi utiliser un éditeur de texte classique. Vous pouvez par exemple vous intéresser à l'éditeur Pulsar[1], libre et multiplateforme.
Premiers pas
[modifier | modifier le wikicode]
Save Notebook As…Lancez le programme Jupyter Lab. Cela vous ouvre une fenêtre dans votre navigateur Internet. Dans cette fenêtre, choisissez Notebook Python 3 : la page devient un éditeur de texte.
Cette page est organisée en cellules ; une cellule est une zone de texte. Vous pouvez donc avoir plusieurs zones de texte, chacune contenant un élément du programme que vous développez. Dans un premier temps, nous allons travailler avec une seule cellule et l'utiliser comme une ligne de commande.
Dans cette cellule, tapez 3 + 2 puis cliquez que le bouton d'évaluation [▶] : cela affiche logiquement le résultat « 5 » en dessous.
Vous pouvez sauvegarder cet embryon de programme avec le menu File > Save Notebook As… Cela crée un fichier portant l'extension de nom de fichier .ipynb.
Jupyter Notebook se présente dans le navigateur Internet (web browser), mais s'utilise comme un navigateur de fichiers (Windows Explorer, Finder, GNOME Commander, Konqueror…). Si l'on veut définir le répertoire de départ, il faut ouvrir Jupyter Notebook avec une commande dans l'Anaconda Prompt :
- Ouvrir
Anaconda Prompt. - Entrer la commande suivante :
jupyter notebook --notebook-dir=chemin.
Où chemin est le chemin d'accès au répertoire voulu. Par exemple, si l'on veut utiliser sous Microsoft Windows le répertoire D:\Temp\, on utilise la commande jupyter notebook --notebook-dir=D:\Temp\.
Vocabulaire
[modifier | modifier le wikicode]- Classe, instance
- Python est un langage orienté objet (oo). Les différents objets manipulés — fonctions, valeurs (numériques, chaînes de caractères)… — dérivent d'archétypes appelés « classe ».
- Par exemple, une matrice NumPy est une mise en application de la classe
numpy.array, on dit que « la matrice est une instance de la classenumpy.array». - Méthode
- Une méthode est une fonction associée à une classe. Quand un objet
Xest une instance de cette classe, on peut avoir accès à la fonction par la la syntaxeX.méthode(). - Par exemple, la classe
numpy.arraypossède une méthode.max()qui donne la valeur maximale contenue dans la matrice. SiXest une instance de la classenumpy.array, alorsX.max()donne le maximum deX. - Ci-dessous, nous verrons les méthodes
.append(),.pop()et.remove()attachées aux objets de type « liste » (voir la section Listes ci-après). - Module, espace de nom
- Un module est un ensemble de classes (fonctions, type de variables…) développées pour un sujet donné.
- Par exemple, le module NumPy est dédié au calcule numérique, le module Scipy est dédié au calcul scientifique le module Matplotlib est dédié au tracé de données.
- Un module se charge avec la commande
import; charger un module permet d'avoir accès à de nouveaux type de variable et à de nouvelles fonctions. - Les modules étant développés séparément, il se peut que des objets de différents modules portent le même nom. Pour éviter les confusions, on fait précéder le nom d'un objet par le nom du module d'où il vient, ou bien de son abréviation. Ainsi, la fonction sinus est fournie par les modules
mathetnumpy, et n'est peut-être pas programmée de la même manière dans les deux modules. Si l'on charge les deux modules, on peut appelermath.sin()etnumpy.sin()(ou biennp.sin()).
Commandes élémentaires
[modifier | modifier le wikicode]Nous avons de base les opérateurs mathématiques élémentaires :
+: addition ;-: soustraction ;*: multiplication ;/: division ;//: division euclidienne (entière) ;%: reste de la division euclidienne ;**: élévation à la puissance[2].
Exemples : cliquez dans la cellule et ajoutez à la suite
print("6/4 =", 6//4, "reste", 6%4)
print(2**0.5) # racine carrée
[▶]
6/4 = 1 reste 2 1.4142135623730951
La division euclidienne peut aussi se faire avec l'instruction divmod() :
a = divmod(6, 4)
print("6/4 =", a[0], "reste", a[1])
Nous voyons ici que la commande print() affiche des informations à l'écran. Les chaînes de caractères peuvent être encadrées de guillemets simple ' ou doubles ". Le croisillon # permet de mettre des commentaires.
L'opérateur + permet de concaténer deux chaînes de caractères.
L'affectation d'une variable se fait avec le signe égal :
a = 5
print(2*a)
[▶]
10
Trois points pour terminer avec les nombres : le type réel à virgule flottante dispose de la méthode .as_integer_ratio() qui transforme un nombre en fraction.
a = 1.5
print(a.as_integer_ratio()) # (3, 2) : fraction 3/2
Ensuite, on peut obtenir l'infini +∞ avec float("inf") ou float("infinity") :
1/float("inf") # 0.0
On peut également avoir le not a number avec float("nan").
Enfin, l'imaginaire se note 1j. De manière générale, on peut écrire 2j, 3.5j… Le type complexe dispose de la méthode conjugate() qui calcule le conjugué.
print(1j**2) # (-1+0j)
a = 2 + 3.5j
print(a.conjugate()) # (2-3.5j)
Les commandes de type x=, où x est un opérateur (+, -, * ou /, //, %, **), permet de modifier une variable (in-place operator) :
a += 0.5est équivalent àa = a + 0.5;a -= 0.5est équivalent àa = a - 0.5;a *= 0.5est équivalent àa = a * 0.5;a /= 0.5est équivalent àa = a / 0.5;- …
Premier tracé graphique
[modifier | modifier le wikicode]
Pour effectuer des tracés graphiques, il faut charger la bibliothèque Matplotlib ; nous choisissons l'option pyplot qui permet d'avoir une syntaxe similaire à Matlab. Pour utiliser cette bibliothèque, il faut écrire import matplotlib.pyplot ; cela donne l'accès à de nouvelles fonctions telles que matplotlib.pyplot.plot().
Comme il est fastidieux d'écrire matplotlib.pyplot avant chaque commande de cette bibliothèque, nous pouvons utiliser une abréviation, par exemple plt, introduite par as lors de l'importation.
Il nous faut aussi pouvoir travailler facilement avec une liste de nombre. Nous chargeons pour cela la bibliothèque NumPy et nous décidons de l'abréger np.
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 2, 0.1)
y = x**2
plt.plot(x, y, label="y = x^2")
plt.xlabel("x")
plt.ylabel("y")
plt.title("Graphes de fonctions")
plt.legend()
La fonction np.arange() permet de créer un vecteur (liste de valeurs) allant de 0 à 2 avec un pas de 0,1. La fonction plt.plot() trace la courbe. Les fonctions plt.xlabel(), plt.ylabel() et plt.title() permettent de mettre des titres aux axes et au graphique. La commande plt.legend() affiche la légende définie dans la commande plt.plot().
Concernant la légende : vous pouvez avoir un rendu de type LaTeX en utilisant les balises $…$ dans le paramètre label de plt.plot() :
plt.plot(x, y, label="$y = x^2$")
Vous remarquerez que la valeur « 2 » n'est pas sur la figure : en effet, selon la logique du « tranchage » (slicing), dans l'expression np.arange(0, 2, 0.1), le nombre 2 est une extrémité exclue du vecteur. Pour l'intégrer, on peut mettre la première valeur qui ne figure pas, ici 2.1 mais cela pourrait poser des problèmes si l'on changeait le pas. Le module NumPy propose une fonction nextafter() qui indique le réel à virgule flottante le plus proche, on pourrait donc écrire np.arange(0, np.nextafter(2, 3), 0.1) (le nombre 3 servant juste à indiquer que l'on veut un nombre supérieur à 2). Mais le plus simple consiste à utiliser la fonction np.linspace() :
x = np.linspace(0, 2, 20) # 20 valeurs entre 0 et 2 inclus
Les chaînes de caractères
[modifier | modifier le wikicode]Une chaîne de caractères est simplement mise entre des guillemets simples '…' ou des guillemets doubles "…". Si le texte contient une apostrophe, on utilise des guillemets doubles ; dans "d'Artagnan", le « ' » est interprété comme un caractère et non comme un délimiteur de chaîne. Et à l'inverse, si on veut utiliser des guillemets doubles dans la chaîne, on la délimite par des guillemets simples : '"En garde !" dit-il'. On peut aussi utiliser la barre de fraction inversée comme « caractère d'échappement » : '"En garde !" s\'exclama d\'Aragnan'.
Pour éviter d'utiliser les échappements \' ou \", si l'encodage du fichier est en Unicode (typiquement utf-8), il est également possible d'utiliser les caractères typographiques : ’ – « – » – “ – ”. Mais ces caractères ne sont pas disponibles facilement à partir du clavier seul.
Dans une variable, les caractères sont numérotés de 0 à n – 1 (si n est le nombre de caractères de la chaîne) :
a = "Python"
a[2] # t
Si l'on veut extraire plusieurs caractères, on utilise deux-points, sous la forme début:fin mais il faut bien comprendre que les numéros correspondent en fait aux interstices entre les caractères. Ainsi, 0:1 va extraire uniquement le premier caractère (celui compris entre les interstices 0 et 1), 0:2 va extraire les deux premiers caractères…
L'indice -1 correspond à l'interstice entre le dernier et l'avant-dernier caractère. Pour résumer :
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
Par exemple
a = "Python"
print(a[0:3]) # Pyt
print(a[3:-1]) # ho
La chaîne intégrale s'obtient avec a[0:] ou a[:]. La chaîne sauf le dernier caractère s'obtient avec a[:-1] ; la chaîne du troisième au dernier caractère s'obtient avec a[2:]. Le dernier caractère s'obtient avec a[-1:] ou bien a[len(a)].
Cette méthode qui consiste à définir des interstices est appelée « découpage en tranches, tranchage », en anglais slicing.
Concernant les caractères non-alphanumériques, on peut utiliser les codes hexadécimaux des caractères Unicode avec l'échappement \u : le caractère U+xxxx s'obtient avec "\uxxxx". Par exemple
print("Bonjour \u263A")
# Bonjour ☺
On peut aussi utiliser les entités HTML :
import html
…
print(html.entities.html5["alpha;"])
# α
L'entité HTML &xxx; s'obtient par html.entities.html5["xxx;"], donc en enlevant la perluète.
Listes et n-uplets
[modifier | modifier le wikicode]
Listes
[modifier | modifier le wikicode]Une liste est une suite d'éléments numérotés. On peut mélanger des nombres et des chaînes de caractère. Pour déclarer une liste, il suffit d'écrire les éléments entre crochets et séparés des virgules. Pour extraire un élément ou un groupe d'éléments, on utilise également le tranchage.
a = ["a", "b", "c", 1, 2, 3]
print(a[2:4]) # ['c', 1]
On peut aussi remplacer une partie de la liste, par exemple :
a = ["a", "b", "c", 1, 2, 3]
a[3] = "foo"
print(a) # ['a', 'b', 'c', 'foo', 2, 3]
Pour ajouter un élément, on peut utiliser la concaténation
a = a + 4
print(a) # ['a', 'b', 'c', 'foo', 2, 3, 4]
ou bien la « méthode » append() :
a.append(4)
Une méthode est une fonction attachée à un type d'objet ; ici, la fonction append() est attachée aux listes.
Pour effacer l'élément i, on utilise
del a[i-1]
Si on veut obtenir la valeur de l'élément avant de le supprimer :
valeur = a.pop([i-1])
Et pour effacer le premier élément dont la valeur est x :
a.remove(x)
La méthode .sort() permet de classer les éléments par ordre croissant, mais uniquement s'ils sont comparable. Typiquement, les éléments doivent être soit tous des nombres, soit tous des chaînes de caractères, mais on ne peut pas mélanger ces deux types ; mais on peut mélanger les entiers et les réels. Pour trier la liste a par ordre décroissant, on utilise a.sort(reverse=True).
Par exemple :
a = [1, 3, 2, 4]
print(a)
# [1, 3, 2, 4]
a.sort()
print(a)
# [1, 2, 3, 4]
a.remove(2)
print(a)
# [1, 3, 4]
On peut construire une liste à partir de n'importe quel objet itérable avec la commande list(itérable) (voir la section Itérable ci-dessous).
N-uplets (tuples)
[modifier | modifier le wikicode]Un n-uplet, en anglais tuple, est similaire à une liste mais on ne peut pas la modifier (ajouter ou changer un élément). L'avantage est qu'elle prend moins de place en mémoire. Elle est définie simplement en séparant les éléments par des virgules. Pour plus de clarté, on peut la mettre entre parenthèses.
b = "a", "b", "c", 1, 2, 3
# ou bien
b = ("a", "b", "c", 1, 2, 3)
Pour faire un n-uplet d'un seul élément, il faut mettre une virgule après l'élément. Pour des raisons de lisibilité, il est conseillé d'utiliser alors des parenthèses.
c = ("un seul élément",)
Notez que la commande print s'applique à un n-uplet, la présence de parenthèses est donc optionnelle.
print "a =", 4
print("a =", 4)
Les booléens
[modifier | modifier le wikicode]Les deux valeurs booléennes sont True et False. Ce sont notamment les résultats des comparaisons avec == (égalité), != (différence), <, >, <= et >=. On peut leur appliquer les opérateurs logiques not, and et or.
a = False
b = 4 <= 5
print(a and b) # False
L'opérateur & est équivalent à and ; le tube | est équivalent à or. Comme pour les opérations arithmétiques, on peut modifier une variable avec &= et |=. Par exemple :
print(True & False) # False
print(True - False) # True
a = True
a &= False # équivalent à a = a & False
print(a) # False
On a normalement pas besoin de tester un booleen : il est son propre test. Par exemple :
a = True
if a:
print("vrai")
Va afficher « vrai ». Si l'on veut toutefois tester la valeur, on utilise alors is (et non pas == comme pour les autres types, même si cela marche aussi avec lees booléens) :
a = True
if a is True:
print("vrai")
pour en savoir plus : Python pour le calcul scientifique/Éléments_de_programmation#Structures_de_contrôle
Les ensembles et les dictionnaires
[modifier | modifier le wikicode]Un ensemble est une liste mais dont l'ordre n'a pas d'importance. Pour cela, il suffit de mettre les éléments entre accolades {…}. On peut aussi utiliser l'instruction set().
set([1, 2, 3]) # {1, 2, 3}
Les opérations possibles sont :
a in E: teste si un élément a fait partie de l'ensemble E (booléen) ;E|F: union des ensembles E et F ;E&F: intersection des ensembles E et F ;E-F: éléments de E qui ne sont pas dans F ;E^F: éléments qui sont dans E ou dans F mais pas dans les deux.
Un dictionnaire est un ensemble de paires « (mot-clef ; valeur) ». Il s'obtient aussi avec des accolades : { "mot-clefs1" : valeur1, "mot-clefs2" : valeurs2, …}. On peut aussi utiliser la commande dict().
dico = dict(a=1, b=2, c=3) # {'a': 1, 'b': 2, 'c': 3}
print(dico["b"]) # 2
Notez que des accolades vides {} créent le dictionnaire vide.
Les espaces de noms
[modifier | modifier le wikicode]De nombreux modules additionnels sont développés pour le langage Python. Lorsque l'on charge un module, pour appeler les fonctions ou classe qu'il apporte, il faut rajouter le nom du module devant le nom de la fonction. Ainsi, si plusieurs modules définissent des fonctions de même nom, il n'y a pas d'ambiguïté. Par exemple, si l'on veut utiliser la fonction mean() apporté par le module numpy, il faut taper numpy.mean().
Le préfixe du nom de fonction ou de classe est appelé l'espace de nom.
Il est possible d'abréger l'espace de nom. Ainsi, ci-dessus, nous avons abrégé numpy en np et ainsi, pour appeler la fonction, il suffit d'écrire np.mean()
Installation et mise à jour de modules
[modifier | modifier le wikicode]Il est possible que certains modules soient absents de votre installation. Pour les installer, on utilise la commande pip (Python installer program), avec la syntaxe suivante :
pip install nomDuModule
Si l'on veut mettre à jour un module avec un version plus récente, on utilise :
pip install --upgrade nomDuModule
Appelable (callable)
[modifier | modifier le wikicode]Dans Python, un « appelable » (callable) est un objet qui dispose d'une méthode __call__(). De manière moins jargonnante, c'est une fonction, un objet que l'on peut appeler avec une paire de parenthèses. Par exemple, l'instruction divmod() est un appelable.
Certaines fonctions renvoient un n-uplet. Par exemple, lorsque 'on fait une régression linéaire avec la commande np.linalg.lstsq(), on obtient un n-uplet de quatre objets (voir Régression_et_optimisation > Régression_linéaire). On peut récupérer soit le n-uplet en entier, soit les éléments un par un. En utilisant l'exemple de la section sur la régression :
resultat = np.linalg.lstsq(X, y)
print(type(resultat))
# <class 'tuple'>
print(resultat)
# (array([4.60203769, 1.90735762]), array([3.16699277]), np.int32(2), array([5.03896036, 1.20456788]))
(a, b, c, d) = np.linalg.lstsq(X, y)
print(a, b, c, d)
# [4.60203769 1.90735762] [3.16699277] 2 [5.03896036 1.20456788]
Si l'on ne veut pas d'un des objets, on peut le remplacer par le tiret de soulignement (underscore) « _ ».
(a, _, _, _) = np.linalg.lstsq(X, y)
print(a)
# [4.60203769 1.90735762]
Itérable
[modifier | modifier le wikicode]Dans Python, un « itérable » est un objet qui peut être utilisé dans une boucle for (voir Éléments_de_programmation > Structures_de_contrôle). Il s'agit de :
- liste :
[…]; - n-uplet (tuple) :
(…); - chaîne de caractère :
"…"ou'…'; - d'ensemble :
set([…]); - de dictionnaires :
dict(…) - d'objet
range(); - d'objet NumPy
np.array()ounp.matrix().
Exemples :
A = [1, 2, 3]
for i in A:
print(i, end=", ")
# 1, 2, 3,
print("")
B = ("A", "B", "C")
for i in B:
print(i, end=" ")
# A, B, C,
print("")
C = "123"
for i in C:
print(i, end=" ")
# 1, 2, 3,
print("")
D = dict(a = 1, b = 2, c = 3)
for i in D:
print(i, end=" ")
# a, b, c,
print("")
Le tranchage (slicing) est en général utilisable sur les itérables ; il ne s'applique pas aux ensembles et dictionnaires.
La commande sorted() trie les itérables par ordre croissant, à condition que les éléments soient comparables (typiquement tous des nombres ou bien tous des chaînes de caractères). Le paramètre reverse=True permet de trier par ordre décroissant. Notez que le résultat est forcément une liste.
A = [1, 2, 3]
A = sorted(A, reverse = True)
print(type(A), A)
# <class 'list'> [3, 2, 1]
B = ("A", "B", "C")
B = sorted(B, reverse = True)
print(type(B), B)
# <class 'list'> ['C', 'B', 'A']
C = "123"
C = sorted(C, reverse = True)
print(type(C), C)
# <class 'list'> ['3', '2', '1']
D = dict(a = 1, b = 2, c = 3)
D = sorted(D, reverse = True)
print(type(D), D)
# <class 'list'> ['c', 'b', 'a']
La commande enumerate() renvoie la liste des éléments de l'itérable en l'associant à son indice (pour la deuxième impression, nous utilisons la définition en compréhension, voir Éléments_de_programmation > Définition_en_compréhension) :
A = ["a", "b", "c"]
print(list(enumerate(A)))
# [(0, 'a'), (1, 'b'), (2, 'c')]
print([a for i, a in enumerate(A) if i % 2 == 0]) # filtre les indices pairs
# ['a', 'c']
On peut utiliser un paramètre start i pour commencer l'énumération à l'élément i + 1.
La commande zip() permet d'itérer sur deux itérables en parallèle.
A = ["a", "b", "c"]
B = [6, 7, 8]
for i in zip(A, B)
# ('a', 6)
# ('b', 7)
# ('c', 8)
On peut utiliser une liste de booléens pour extraire une partie d'un itérable, avec la fonction compress() du module itertools.
from itertools import compress
A = [1, 2, 3, 4, 5]
booleen = [True, False, True, False, True]
print(list(compress(A, booleen)))
# [1, 3, 5]
Cette fonction est beaucoup plus performante qu'une extraction itérative de type [a for i, a in enumerate(A) if booleen[i]] ou [a for (a, b) in zip(A, booleen) if b].
for. On peut construire directement un itérateur avec la fonction iter(), ou bien avec la fonction reversed() auquel cas le flux de données est inversé. Les itérateurs possèdent la méthode __next__() qui renvoie l'élément suivant (et le premier élément au premier appel).
On peut transformer un itérateur en liste ou en n-uplet, mais cela interrompt alors le flux de données (on ne peut plus utiliser .__next__()).
A = [1, 2, 3, 4, 5]
A = iter(A)
print(A)
# <list_iterator object at 0x00000204181AB3A0>
print(A.__next__())
# 1
print(A.__next__())
# 2
print(list(A))
# [3, 4, 5]
B = ("A", "B", "C", "D", "E")
B = reversed(B)
print(B)
# <reversed object at 0x0000020417A7E9B0>
print(B.__next__())
# E
print(B.__next__())
# D
print(tuple(B))
# ('C', 'B', 'A')
Notes et références
[modifier | modifier le wikicode]- ↑ « Pulsar Edit », sur Pulsar (consulté le 2 septembre 2025).
- ↑ Note : l'accent circonflexe «
^» (caret), utilisé dans de nombreux langages pour l'élévation à la puissance, effectue ici un « ou exclusif » (XOR) bit à bit.
Python pour le calcul scientifique < ↑ > Premiers programmes