10.2. Entrée, sortie et erreur standard
Les utilisateurs d'UNIX sont déjà familiers avec les concepts d'entrée standard, de sortie standard et d'erreur standard. Cette section s'adresse
aux autres.
La sortie standard et l'erreur standard (communément abrégé en stdout et en stderr) sont des canaux de communication (pipes) intégrés à chaque système UNIX. Lorsque vous affichez (fonction print) quelque chose, il est dirigé vers le canal de communication stdout; quand votre programme plante et affiche des informations de débogage (comme un traceback en Python), elles sont envoyées vers le canal de communication stderr. Chacun de ces deux canaux sont d'ordinaire simplement connectés à la fenêtre du terminal avec laquelle vous travaillez
et de cette façon vous voyez s'afficher la sortie du programme ou l'information de débogage s'il plante. (Si vous travaillez
sur un système pourvu d'un IDE Python fenêtré, stdout et stderr sont redirigés par défaut vers la «Fenêtre Interactive».)
Exemple 10.8. Introduction à stdout et à stderr
>>> for i in range(3):
... print 'Dive in'
Dive in
Dive in
Dive in
>>> import sys
>>> for i in range(3):
... sys.stdout.write('Dive in')
Dive inDive inDive in
>>> for i in range(3):
... sys.stderr.write('Dive in')
Dive inDive inDive in
|
Comme vous l'avez vu dans l'Exemple 6.9, «Compteurs simples», vous pouvez utiliser la fonction prédéfinie de Python range pour construire un simple compteur de boucles qui répète une instruction un nombre déterminé de fois.
|
|
stdout est un pseudo objet-fichier; appeler sa fonction write affichera toutes les chaînes que vous lui donnez. En fait, c'est bien ce que fait la fonction print; elle ajoute un retour chariot à la fin de la chaîne que vous affichez et appelle sys.stdout.write.
|
|
Dans le cas le plus simple, stdout et stderr envoient leur sortie au même endroit : l'IDE Python (si vous en utilisez un), ou la console (si vous avez lancé Python à partir de la ligne de commande). Comme stdout, stderr n'ajoute pas de retour chariot pour vous; si vous en avez besoin, ajoutez-les vous-même.
|
stdout et stderr sont toutes les deux des pseudo objet-fichiers, comme ceux dont il a été question dans la Section 10.1, «Extraire les sources de données en entrée», mais ils sont tous les deux en écriture seule. Ils n'ont pas de méthode read, seulement une méthode write. Ils n'en restent pas moins des pseudo objet-fichiers auxquels vous pouvez assigner n'importe quel autre fichier - ou pseudo
objet-fichier afin d'en rediriger la sortie.
Rediriger stderr fonctionne exactement de la même manière, en utilisant sys.stderr au lieu de sys.stdout.
Exemple 10.10. Rediriger un message d'erreur
[you@localhost kgp]$ python stderr.py
[you@localhost kgp]$ cat error.log
Traceback (most recent line last):
File "stderr.py", line 5, in ?
raise Exception, 'this error will be logged'
Exception: this error will be loggedSi vous ne l’avez pas déjà fait, vous pouvez télécharger cet exemple ainsi que les autres exemples du livre.
import sys
fsock = open('error.log', 'w')
sys.stderr = fsock
raise Exception, 'this error will be logged'
|
Ouvre le fichier journal où vous voulez enregistrer l'information de débogage. |
|
Redirige l'erreur standard en affectant à stderr l'objet-fichier correspondant au fichier journal nouvellement créé.
|
|
Déclenche une exception. Notez que sur l'écran de sortie rien ne s'affiche. Toute l'information de traceback a été écrite dans error.log.
|
|
Remarquez également que vous ne fermez pas explicitement votre fichier journal, ni ne restaurez stderr dans son état d'origine. Il n'y a pas d'erreur, puisqu'une fois le programme planté (à cause de l'exception), Python nettoiera et fermera le fichier pour nous et cela n'a pas d'importance que stderr soit restauré, puisque, comme je l'ai signalé, le programme plante et Python se termine. Un retour à l'état antérieur est plus important pour stdout, si vous souhaiter continuer à travailler avec le même script ultérieurement.
|
Puisqu'il est si trivial d'écrire des messages d'erreurs sur le canal d'erreur standard, il existe une syntaxe abrégée qui
peut être utilisée plutôt que de s'embêter à effectuer une redirection complète.
Exemple 10.11. Afficher un message sur stderr
>>> print 'entering function'
entering function
>>> import sys
>>> print >> sys.stderr, 'entering function'
entering function
|
Cette syntaxe abrégée de l'expression print peut être utilisée pour écrire dans tout fichier ou pseudo objet-fichier. Dans cet exemple, vous pouvez rediriger une seule
expression print vers stderr sans affecter les expressions print ultérieures.
|
L'entrée standard, de l'autre côté, est un objet-fichier en lecture seule et représente les données circulant entre un programme
et un programme exécuté antérieurement. Cela n'a probablement pas grand sens pour les utilisateurs chevronnés de Mac OS, ou même pour les utilisateurs de Windows à moins que vous ne soyez coutumier de la ligne de commande MS-DOS. Son principe de fonctionnement vous permet de construire une chaîne de commandes sur une seule ligne, de telle sorte que
la sortie d'un premier programme devienne l'entrée du programme suivant dans la chaîne. Le premier programme retourne simplement
un résultat vers la sortie standard (sans effectuer lui-même une redirection spéciale, sinon le renvoi en sortie de quelques
instructions print ou que sais-je encore), le programme suivant lit l'entrée standard, et le système d'exploitation se charge de connecter la
sortie d'un programme à l'entrée du programme suivant.
Exemple 10.12. Chaîner les commandes
[you@localhost kgp]$ python kgp.py -g binary.xml
01100111
[you@localhost kgp]$ cat binary.xml
<?xml version="1.0"?>
<!DOCTYPE grammar PUBLIC "-//diveintopython.org//DTD Kant Generator Pro v1.0//EN" "kgp.dtd">
<grammar>
<ref id="bit">
<p>0</p>
<p>1</p>
</ref>
<ref id="byte">
<p><xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/>\
<xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/></p>
</ref>
</grammar>
[you@localhost kgp]$ cat binary.xml | python kgp.py -g -
10110001
|
Comme vous l'aviez vu dans la Section 9.1, «Plonger», cette commande affiche une chaîne de huit bits aléatoires, 0 ou 1.
|
|
Cette commande affiche simplement la totalité du contenu de binary.xml. (les utilisateurs de Windows doivent utiliser type au lieu de cat.)
|
|
Cette commande affiche le contenu de binary.xml, mais le caractère «|», appelé «pipe», signifie que le contenu ne sera pas affiché à l'écran. A la place, il deviendra l'entrée standard de la prochaine commande
qui dans ce cas appelle votre script Python.
|
|
Plutôt que de spécifier un module (comme binary.xml), vous spécifiez «-», ce qui oblige votre script à charger la grammaire à partir de l'entrée standard au lieu d'un fichier particulier sur le
disque. (Vous en saurez plus à ce propos dans le prochain exemple.) Ainsi le résultat est le même qu'avec la syntaxe précédente,
où vous spécifiiez directement le nom du fichier de grammaire, mais pensez en plus aux nombreuses possibilités qui s'offrent
à vous. Plutôt que de simplement exécuter cat binary.xml, vous pourriez lancer un premier script qui générerait dynamiquement une grammaire que vous redirigeriez vers votre script.
Les données pourraient provenir de n'importe où : une base de données, un méta-script générateur de grammaire, ou que sais-je
encore. L'important est que vous n'avez pas besoin de modifier votre script kgp.py pour tenir compte de cette fonctionnalité. Tout ce dont vous avez besoin, c'est de pouvoir récupérer le fichier de grammaire
à partir de l'entrée standard et alors vous pouvez confier toute la logique restante à un autre programme.
|
Comment donc notre script «sait»-il qu'il doit lire à partir de l'entrée standard quand le fichier de grammaire correspond à «-» ? Cela n'a rien de magique; juste logique.
Exemple 10.13. Lire à partir de l'entrée standard dans kgp.py
def openAnything(source):
if source == "-":
import sys
return sys.stdin
import urllib
try:
[... snip ...]
|
Il s'agit de la fonction openAnything de toolbox.py, que vous aviez précédemment examinée dans la Section 10.1, «Extraire les sources de données en entrée». Tout ce que vous avez fait est d'ajouter trois lignes de code au début de cette fonction pour tester si la source correspond
à «-»; si c'est le cas, vous retournez sys.stdin. Rien de plus ! Souvenez-vous que stdin est un pseudo objet-fichier pourvu d'une méthode read, si bien que le reste du code (dans kgp.py où vous appelez openAnything) ne change pas d'un pouce.
|