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
 
Jupyter.

Nous utilisons la distribution Anaconda : https://www.anaconda.com/

Suivez les instructions d'installation selon votre système. Choisissez « Python 3 ».

 Sous MacOS X, il peut être nécessaire de créer un alias vers le programme Jupyter-lab ; ce programme se trouve habituellement au chemin /anaconda3/bin/jupyter-lab.

Bien entendu, vous pouvez aussi utiliser un éditeur de texte classique. Vous pouvez par exemple vous intéresser à l'éditeur Atom[1], libre et multiplateforme.

Premiers pas

modifier
 
Fenêtre Python/Jupyter Lab dans Firefox : fonction 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.

Commandes élémentaires

modifier

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.5 est équivalent à a = a + 0.5 ;
  • a -= 0.5 est équivalent à a = a - 0.5 ;
  • a *= 0.5 est équivalent à a = a * 0.5 ;
  • a /= 0.5 est équivalent à a = a / 0.5 ;

Premier tracé graphique

modifier
 
Graphe de la fonction carré avec Python/Matplotlib.

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

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.

Listes et n-uplets

modifier
 
Découpage en tranche (slicing) : indexation des éléments à extraire d'une chaîne, d'une liste ou d'un n-uplet en Python.

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)

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

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
print(a) # False

Les ensembles et les dictionnaires

modifier

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

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()

Notes et références

modifier
  1. https://atom.io/ ; GitHub a annoncé qu'il arrêtait le développement d'Atom à partir de fin 2022 (https://github.blog/2022-06-08-sunsetting-atom/) mais la dernière version reste disponible.
  2. 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