Entrées-sorties#
Commencer une ligne avec !
vous donne accès aux commandes du shell. Par exemple, ! ls
(pour Linux ou Mac) ou ! dir
(pour Windows) permet d’afficher les fichiers présents dans votre répertoire de travail :
! ls
01-dictionnaires-pandas.ipynb banksy.txt exoplanets.csv
02-logique-filtrage.ipynb europe.csv exoplanets.dat
03-iteration.ipynb europe.pkl test.txt
04-fonctions.ipynb exo-write.txt verne-lune.txt
05-entrees-sorties.ipynb exoplanets-SI.dat
Vidéo: Lire et écrire#
Lire un fichier texte#
Nous avons extrait un passage du livre De la Terre à la Lune, trajet direct en 97 heures 20 minutes, paru en 1865 et écrit par Jules Verne (1828-1905). Il est disponible librement sur le site du Projet Gutenberg. Cet extrait est enregistré dans le fichier nommé verne-lune.txt.
Pour pouvoir importer le texte dans Python, il faut d’abord ouvrir le fichier avec la fonction open()
:
# Ouverture du fichier texte
file = open('verne-lune.txt', mode = 'r', encoding = 'utf-8')
Nous avons donné à l’argument mode
la valeur r
pour ouvrir le fichier seulement en lecture et pas en écriture (read-only). Cela permet d’empêcher toute modification du fichier. Afin de lire tout le fichier, on peut utiliser la méthode .read()
sur la variable file
:
# Lecture du fichier
print(file.read())
_Longs's-Peak, 12 décembre._
A MM. LES MEMBRES DU BUREAU DE L'OBSERVATOIRE DE CAMBRIDGE.
_Le projectile lancé par la Columbiad de Stone's-Hill a été aperçu par
MM. Belfast et J.-T. Maston, le 12 décembre, à huit heures
quarante-sept minutes du soir, la Lune étant entrée dans son dernier
quartier.
Ce projectile n'est point arrivé à son but. Il a passé à côté, mais
assez près, cependant, pour être retenu par l'attraction lunaire.
Là, son mouvement rectiligne s'est changé en un mouvement circulaire
d'une rapidité vertigineuse, et il a été entraîné suivant une orbite
elliptique autour de la Lune, dont il est devenu le véritable
satellite.
Les éléments de ce nouvel astre n'ont pas encore pu être déterminés.
On ne connaît ni sa vitesse de translation, ni sa vitesse de rotation.
La distance qui le sépare de la surface de la Lune peut être évaluée à
deux mille huit cent trente-trois milles environ (-- 4,500 lieues).
Maintenant, deux hypothèses peuvent se produire et amener une
modification dans l'état des choses:
Ou l'attraction de la Lune finira par l'emporter, et les voyageurs
atteindront le but de leur voyage;
Ou, maintenu dans un ordre immutable, le projectile gravitera autour
du disque lunaire jusqu'à la fin des siècles.
C'est ce que les observations apprendront un jour, mais jusqu'ici la
tentative du Gun-Club n'a eu d'autre résultat que de doter d'un nouvel
astre notre système solaire._
J.-M. BELFAST.
Une fois fini, il faut libérer la mémoire en fermant le fichier. On peut vérifier si le fichier est ouvert ou fermé en affichant l’attribut closed
de l’objet file
:
# Vérifie si le fichier est fermé
print(file.closed)
False
Le fichier n’est pas fermé. On peut le fermer avec la méthode .close()
:
# Fermeture du fichier
file.close()
# Vérifie si le fichier est fermé
print(file.closed)
True
On peut aussi ne lire qu’une seule ligne avec la méthode .readline()
. Si on utilise de nouveau cette méthode, alors Python lit la ligne suivante :
# Ouverture du fichier texte
file = open('verne-lune.txt', mode = 'r', encoding = 'utf-8')
# Lecture des 3 premières lignes
print(file.readline())
print(file.readline())
print(file.readline())
# Fermeture du fichier
file.close()
_Longs's-Peak, 12 décembre._
A MM. LES MEMBRES DU BUREAU DE L'OBSERVATOIRE DE CAMBRIDGE.
Exercice#
Ouvrir le fichier banksy.txt en lecture seul
Afficher le fichier
Fermer le fichier
Show code cell source
# Ouverture du fichier texte
file = open('banksy.txt', mode = 'r', encoding = 'utf-8')
# Lecture du fichier
print(file.read())
# Fermeture du fichier
file.close()
.s$$$Ss.
.8, $$$. _. . ..sS$$$$$" ...,.;
o. ,@.. 88 =.$"$' ' ..sS$$$$$$$$$$$$s. _;"'
@@@.@@@. .88. ` ` ""l. .sS$$.._.sS$$$$$$$$$$$$S'"'
.@@@q@@.8888o. .s$$$$$$$$$$$$$$$$$$$$$'
.:`@@@@33333. .>$$$$$$$$$$$$$$$$$$$$'
.: `@@@@333' ..>$$$$$$$$$$$$$$$$$$$'
: `@@333. `., s$$$$$$$$$$$$$$$$$'
: `@33 $$ S.s$$$$$$$$$$$$$$$$$'
.S `Y ..` ,"$' `$$$$$$$$$$$$$$
$s . ..S$s, . .`$$$$$$$$$$$$.
$s ., ,s ,$$$$,,sS$s.$$$$$$$$$$$$$.
/ /$$SsS.s. ..s$$$$$$$$$$$$$$$$$$$$$$$$$.
/`.`$$$$$dN.ssS$$'`$$$$$$$$$$$$$$$$$$$$$$$.
/// `$$$$$$$$$' `$$$$$$$$$$$$$$$$$$$$$$.
///| `S$$S$' `$$$$$$$$$$$$$$$$$$$$$$.
/ / $$$$$$$$$$$$$$$$$$$$$.
`$$$$$$$$$$$$$$$$$$$$$s.
$$$"' .?T$$$$$$$
.$' ... ?$$#\
! -=S$$$$$s
.! -=s$$' `$=-_ :
, .$$$' `$, .|
, .$$$' . ,
, ..$$$'
.s$$$' `s .
. .s$$$$' $s. ..$s
. .s$$$$' `$s=s$$$
.$$$$' , $$s
` " .$$' $$$
, s$$' . $$$s
` .s..s$' .s ,$$
.s$$$' "s$$$,
- $$$' .$$$$.
." .s$$s .$',',$.
$s.s$$$$S.............. ................ $$....s$s......
`""' ` ```""""""""""""""" `"" ``
Gestionnaire de contexte#
Le flux d’instructions introduit précédemment peut poser problème : si une erreur intervient avant la fermeture du fichier (avec la méthode .close()
), celui-ci ne sera pas fermé et des données pourraient être perdues.
La meilleure manière de faire est d’utiliser un gestionnaire de contexte, que l’on utilise avec l’instruction with
de la façon suivante :
# Ouverture et lecture du fichier avec un gestionnaire de contexte
with open('verne-lune.txt', mode = 'r', encoding = 'utf-8') as file:
print(file.readline())
_Longs's-Peak, 12 décembre._
La fermeture du fichier est alors implicite. On peut aussi écrire dans un fichier avec la méthode .write()
. Pour cela, il faut ouvrir le fichier avec le mode 'w'
(write) :
# Ouverture et écriture dans un fichier avec un gestionnaire de contexte
with open('test.txt', mode = 'w') as file:
file.write('Je sais écrire dans un fichier !\nSuper !')
Le caractère spécial \n
dans la chaîne de caractères permet le retour à la ligne.
Il existe de nombreux modes d’ouverture d’un fichier, les principaux étant :
Caractère |
Signification |
---|---|
|
ouvre en lecture (par défaut) |
|
ouvre en écriture, tronquant le fichier |
|
ouvre pour une création exclusive, échouant si le fichier existe déjà |
|
ouvre en écriture, ajoutant à la fin du fichier s’il existe |
Exercice#
En utilisant un gestionnaire de contexte et une boucle for
:
Afficher la ligne 13 du fichier verne-lune.txt. Pour cela il faut exécuter 12 fois la méthode
.readline()
sansprint()
, puis une treizième fois avecprint()
Créez un fichier nommé exo-write.txt dans lequel vous écrirez tous les entiers entre 1 et 100 (avec un entier par ligne)
Show code cell source
# 1. Ouverture et lecture du fichier avec un gestionnaire de contexte
with open('verne-lune.txt', mode = 'r', encoding = 'utf-8') as file:
for i in range(12):
file.readline()
print(file.readline())
Là, son mouvement rectiligne s'est changé en un mouvement circulaire
Show code cell source
# 2. Ouverture et écriture dans un fichier avec un gestionnaire de contexte
with open('exo-write.txt', mode = 'w') as file:
for i in range(1, 101):
file.write(str(i) + '\n')
Vidéos: Outils supplémentaires#
Lire le clavier#
La fonction input()
lit tout ce qui est écrit au clavier comme une chaîne de caractères :
# Lire ce qui est écrit au clavier (finir avec la touche entrée)
chaine = input("Entrez votre message avec input:\n")
# Afficher ce qui a été écrit
print("Vous avez entré :", chaine)
print(type(chaine))
---------------------------------------------------------------------------
StdinNotImplementedError Traceback (most recent call last)
Cell In[14], line 2
1 # Lire ce qui est écrit au clavier (finir avec la touche entrée)
----> 2 chaine = input("Entrez votre message avec input:\n")
4 # Afficher ce qui a été écrit
5 print("Vous avez entré :", chaine)
File /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/ipykernel/kernelbase.py:1269, in Kernel.raw_input(self, prompt)
1267 if not self._allow_stdin:
1268 msg = "raw_input was called, but this frontend does not support input requests."
-> 1269 raise StdinNotImplementedError(msg)
1270 return self._input_request(
1271 str(prompt),
1272 self._parent_ident["shell"],
1273 self.get_parent("shell"),
1274 password=False,
1275 )
StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
Exercice#
Avec la fonction
input()
, demander à l’utilisateur d’entrer un entier au clavier et affecter la valeur à une variablesn
Convertir la variable
sn
en entier avec la fonctionint()
, et affecter la valeur à une variablen
Afficher le carré de
n
à l’écran
Show code cell source
# Entrée au clavier
sn = input("Entrer un entier :\n")
# Conversion en entier
n = int(sn)
# Afficher le carré de n
print(n * n)
---------------------------------------------------------------------------
StdinNotImplementedError Traceback (most recent call last)
Cell In[15], line 2
1 # Entrée au clavier
----> 2 sn = input("Entrer un entier :\n")
4 # Conversion en entier
5 n = int(sn)
File /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/ipykernel/kernelbase.py:1269, in Kernel.raw_input(self, prompt)
1267 if not self._allow_stdin:
1268 msg = "raw_input was called, but this frontend does not support input requests."
-> 1269 raise StdinNotImplementedError(msg)
1270 return self._input_request(
1271 str(prompt),
1272 self._parent_ident["shell"],
1273 self.get_parent("shell"),
1274 password=False,
1275 )
StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
Format défini#
Dans l’exemple suivant nous affichons les valeurs des variables x
et n
avec un format défini. La syntaxe est similaire à celle d’autres langages comme Matlab ou C :
# Création des variables
x = 45.9876
n = 6
# Affichage avec un format défini
print('x = %5.3f, n = %d' % (x, n))
print('x = %5.3e, n = %5d' % (x, n))
x = 45.988, n = 6
x = 4.599e+01, n = 6
%5d
5
est le nombre de caractères imprimés, y compris les espaces blancsd
indique un entier
%5.3f
5
est le nombre total de caractères imprimés, y compris le signe - si le chiffre est négatif, ou tout autre caractère. Cependant le nombre de caractères imprimés sera supérieur à ce chiffre si il est trop petit pour pouvoir atteindre la pécision requise dans l’affichage : dans l’exemple donné, le nombre total de caractères imprimés est 63
est le nombre de chiffres après le point décimal (6 par défaut)f
donne le type, ici le format fixe pour un réel
%5.3e
la seule différence est
e
qui donne le type d’affichage exponentiel
Une syntaxe alternative a été introduite depuis Python 2.6 avec la méthode .format()
des chaînes de caractères :
print('x = {:f}, n = {}'.format(x, n))
print('x = {:8.3f}, n = {:d}'.format(x, n))
x = 45.987600, n = 6
x = 45.988, n = 6
Un bon endroit pour découvrir toutes les possibilités offertes par le formatage en Python, dans les deux styles d’écriture, est le site pyformat.
Lire et écrire des tableaux Numpy#
Pour importer les données d’un fichier texte dans un tableau Numpy on peut utiliser la fonction loadtxt()
. Chaque ligne du fichier doit avoir le même nombre de valeurs. Par défaut les lignes commençant par # ne sont pas lues. Elles sont généralement utilisées pour décrire les données dans l’en-tête du fichier.
Nous disposons d’un fichier exoplanets.dat qui décrit les caractéristiques de 256 exoplanètes. Ces données sont tirées du site internet exoplanets.org. Chaque ligne du fichier caractérise une exoplanète et l’étoile autour de laquelle elle gravite. Les quatre colonnes donnent :
le demi-grand axe de l’orbite parcourue par la planète en unités astronomiques ;
la période orbitale en jours ;
la masse de la planète en unités de masse de Jupiter ;
la masse de l’étoile autour de laquelle la planète gravite en unités de masse solaire.
Importons les données dans la variable data
grâce à la fonction loadtxt()
de Numpy :
# Importation du module numpy
import numpy as np
# Importation des données
data = np.loadtxt('exoplanets.dat')
Nous vérifions que data
est bien un tableau Numpy de forme (256, 4) :
print(type(data))
print(data.shape)
<class 'numpy.ndarray'>
(256, 4)
Plutôt que de créer un tableau 2D, il est possible de créer 4 tableaux 1D contenant les données de chaque colonne directement avec l’argument unpack
:
a, p, mp, me = np.loadtxt('exoplanets.dat', unpack = True)
Nous voulons changer les unités des données en unités S.I. et sauvegarder les nouvelles données dans un nouveau fichier. D’abord, changeons les unités :
# Set constants
au2m = 149597870700. # Conversion from astronomical units to m
day2seconds = 24. * 60. * 60. # Conversion from day to seconds
M_jupiter = 1.898e27 # Jupiter mass in kg
M_sun = 1.9891e30 # Solar mass in kg
# Change units to SI
a_SI = a * au2m
p_SI = p * day2seconds
mp_SI = mp * M_jupiter
me_SI = me * M_sun
On peut ensuite sauvegarder les nouvelles données dans le fichier exoplanets-SI.dat avec la fonction Numpy savetxt()
:
np.savetxt('exoplanets-SI.dat', np.c_[a_SI, p_SI, mp_SI, me_SI], fmt = '%10.3e')
On a utilisé la commande Numpy c_[]
pour concaténer en colonnes les tableaux 1D. L’argument fmt
permet de spécifier le format d’écriture, avec la même syntaxe vue plus haut pour print
.
Importer des données mixtes avec Pandas#
Il arrive souvent que les données à importer soient de types différents. Il n’est pas très pratique de les importer avec Numpy. On peut alors utiliser le module Pandas. Nous avons sauvegardé un fichier plus complet contenant les informations de 3236 exoplanètes, sous la forme d’un fichier csv. La signification des différentes colonnes est expliquée sur le site exoplanets.org. Ces colonnes contiennent à la fois des données numériques et du texte. On ne peut pas utiliser la fonction loadtxt()
.
Comme expliqué dans le module Dictionnaires et Pandas, on utilise la fonction read_csv()
pour importer et créer un DataFrame :
# Importer le module pandas
import pandas as pd
# Importer les données dans un DataFrame
data = pd.read_csv('exoplanets.csv')
Nous vérifions que les données ont bien été importées :
# Affichage des 3 premières lignes
data.head(n = 3)
NAME | MSINI | A | PER | ECC | OM | T0 | K | ORBREF | ORBURL | FIRSTREF | FIRSTURL | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Kepler-107 d | NaN | 0.078010 | 7.958203 | NaN | 90.0 | 2.454971e+06 | NaN | Rowe 2014 | http://adsabs.harvard.edu/abs/2014arXiv1402.6534R | Rowe 2014 | http://adsabs.harvard.edu/abs/2014arXiv1402.6534R |
1 | Kepler-1049 b | NaN | 0.034472 | 3.273461 | 0.0 | 90.0 | NaN | NaN | Morton 2016 | http://adsabs.harvard.edu/abs/2016ApJ...822...86M | Morton 2016 | http://adsabs.harvard.edu/abs/2016ApJ...822...86M |
2 | Kepler-813 b | NaN | 0.137610 | 19.129473 | 0.0 | 90.0 | NaN | NaN | Morton 2016 | http://adsabs.harvard.edu/abs/2016ApJ...822...86M | Morton 2016 | http://adsabs.harvard.edu/abs/2016ApJ...822...86M |
On voit que les données manquantes ont été remplacées par NaN (Not-a-Number).
On peut maintenant utiliser ces données, par exemple pour savoir combien de planètes ont été reportées pour la première fois dans la référence Morton 2016 :
# Nombre de planètes dans Morton 2016
print(np.sum(data['FIRSTREF'] == 'Morton 2016'))
1283
Remarquez que dans cette commande on a sommé les éléments d’un objet Series contenant des booléens. Dans ce cas, la valeur True
est considérée comme un 1
, et la valeur False
comme un 0
.