Dans ce chapitre vous plongerez dans les exceptions, les objets-fichiers, les boucles for et les modules os et sys. Si vous avez utilisé les exceptions dans un autre langage de programmation, vous pouvez survoler la première section pour
avoir une idée de la syntaxe de Python. Assurez-vous de reprendre une lecture détaillée pour l'utilisation des fichiers.
Comme beaucoup de langages orientés objet,
Python gère les exception à l'aide de blocs
try...except.
Python utilise try...except pour gérer les exceptions et
raise pour les générer. Java et C++ utilisent
try...catch pour gérer les exceptions et
throw pour les générer.
Les exceptions sont partout en Python,
pratiquement chaque module de la librairie standard
Python les utilise et
Python lui-même en déclenchera dans de
nombreuses circonstances différentes. Vous les avez déjà vu à plusieurs
reprises tout au long de ce livre.
Dans chacun de ces cas, nous ne faisions qu'expérimenter à l'aide
de l'IDEPython : une
erreur se produisait, l'exception était affichée (éventuellement, en
fonction de votre IDE, dans un rouge détonnant) et
c'était tout. C'est ce que l'on appelle une exception
non-gérée, lorsque l'exception a été déclenchée, il
n'y avait pas de code pour la prendre en charge explicitement, elle est
donc remontée jusqu'à Python qui l'a traité
selon la méthode par défaut, qui est d'afficher une information de
débogage et d'abandonner. Dans l'IDE ce n'est pas un
problème, mais si cela arrivait pendant le déroulement d'un de vos
programmes Python réels, le programme dans
son ensemble serait arrété.
Cependant, une exception ne doit pas forcément entrainer le
plantage complet d'un programme. Les exceptions, lorsqu'elles sont
déclenchées, peuvent être gérées. Parfois une
exception se produit parcequ'il y a réellement un bogue dans votre code
(comme tenter d'accéder à une variable qui n'existe pas), mais souvent,
une exception est un évènement que vous pouvez prévoir. Si vous ouvrez
un fichier, il peut ne pas exister, si vous vous connectez à une base de
données, elle peut être indisponible, ou peut-être n'avez-vous pas les
droits nécéssaires pour y accéder. Si vous savez qu'une ligne de code
est susceptible de déclencher un exception, vous devriez gérer
l'exception avec un bloc try...except.
Exemple 6.1. Ouverture d'un fichier inexistant
>>> fsock = open("/notthere", "r")Traceback (innermost last):
File "<interactive input>", line 1, in ?
IOError: [Errno 2] No such file or directory: '/notthere'>>> try:... fsock = open("/notthere")... except IOError:... print"The file does not exist, exiting gracefully"... print"This line will always print"The file does not exist, exiting gracefully
This line will always print
En utilisant la fonction prédéfinie open,
nous pouvons ouvrir un fichier en lecture (nous verrons
open plus en détail dans la section
suivante). Mais le fichier n'existe pas, ce qui déclenche une
exception IOError. Comme nous n'avons pas
fourni de gestionnaire pour l'exception
IOError, Python
se contente d'afficher des informations de débogage et
abandonne.
Nous allons essayer d'ouvrir le même fichier non-existant,
mais cette fois à l'intérieur d'un bloc
try...except.
Quand la méthode open déclenche une
exception IOError, nous sommes prêts. La
ligne except IOError: intercepte l'exception et
exécute notre propre bloc de code, qui en l'occurence ne fait
qu'afficher un message d'erreur plus agréable.
Une fois qu'une exception a été traitée, le traitement
continue normalement à la première ligne après le bloc
try...except. Notez que cette ligne sera
toujours affichée, qu'une exception se produise ou pas. Si vous
aviez vraiment un fichier appelé notthere
dans votre répertoire racine, l'appel a open
réussirait, la clause except serait ignorée,
mais cette ligne serait quand même exécutée.
Les exceptions peuvent sembler hostiles (après tout, si vous ne
les interceptez pas, votre programme plante), mais réflechissez à
l'alternative. Voudriez-vous plutôt un objet-fichier inutilisable
pointant vers un fichier non-existant ? De toute manière, vous auriez
quand même à vérifier sa validité, sinon votre programme produirait des
erreurs bizarres plus loin dont vous auriez à retrouver la source. Je
suis sûr que vous avez déjà fait cela, ce n'est pas drôle. Avec les
exceptions, les erreurs se produisent immédiatement et vous pouvez les
gérer de manière standardisée à la source du problème.
6.1.1. Utilisation d'exceptions pour d'autres cas que la gestion d'erreur
Il y a de nombreux autres usages pour les exceptions en dehors de
la prise en compte de véritables conditions d'erreurs. Un des usages
commun dans la bibliothèque standard Python est
d'essayer d'importer un module, puis de vérifier si cela à marché.
Importer un module qui n'existe pas déclenchera une exception
ImportError. Vous pouvez utiliser cela pour
définir des niveaux multiples de fonctionnalité basé sur la
disponibilité des modules à l'exécution, ou pour supporter plusieurs
plateformes (dans ce cas le code spécifique à chaque plateforme est
séparé dans différents modules).
Vous pouvez aussi définir vos propre exceptions en créant un
classe qui hérite de la classe prédéfinie
Exception et déclencher vos exceptions avec
l'instruction raise. Cela dépasse le champ de cette
section, voyez la section «Pour en savoir plus» si vous
êtes intéressé.
L'exemple suivant démontre l'utilisation d'une exception pour le support d'une fonctionnalité spécifique à une plate-forme.
Ce code vient du module getpass, un module enveloppe pour obtenir un mot de passe de l'utilisateur. Obtenir un mot de passe est fait de manière différente
sous UNIX, Windows et MacOS, mais ce code encapsule toutes ces différences.
Exemple 6.2. Support de fonctionnalités propre à une plate-forme
# Bind the name getpass to the appropriate functiontry:
import termios, TERMIOS except ImportError:
try:
import msvcrt except ImportError:
try:
from EasyDialogs import AskPassword except ImportError:
getpass = default_getpass else:
getpass = AskPassword
else:
getpass = win_getpass
else:
getpass = unix_getpass
termios est un
module spécifique à UNIX qui fournit un
contrôle de bas niveau sur le terminal d'entrée. Si ce module
n'est pas disponible (parcequ'il n'est pas sur votre système ou
que votre système ne le supporte pas), l'import échoue et
Python déclenche une exception
ImportError, que nous interceptons.
OK, nous n'avons pas termios, essayons donc msvcrt, qui est un module spécifique
à Windows qui fournit une API pour de
nombreuses fonctions utiles des services d'exécution de Microsoft
Visual C++. Si l'import échoue,
Python déclenche une exception
ImportError, que nous interceptons.
Si les deux premiers n'ont pas marché, nous essayons
d'importer une fonction de EasyDialogs, qui est un module
spécifique à MacOS qui
fournit des fonctions pour afficher des boîtes de dialogue de
différents types. Encore une fois, si cette import échoue,
Python déclenche une exception
ImportError, que nous interceptons.
Aucun de ces modules spécifiques n'est disponible (ce qui
est possible puisque Python a été porté
sur de nombreuses plateformes), nous devons donc nous replier sur
la fonction de saisie de mot de passe par défaut (qui est définie
ailleurs dans le module getpass). Remarquez ce que nous
faison là : nous assignons la fonction
default_getpass à la variable
getpass. Si vous lisez la documentation
officielle de getpass,
elle vous dit que le module getpass définit une fonction
getpass. C'est comme ça qu'il le fait, en
assignant getpass à la bonne fonction pour
votre plateforme. Quand vous appelez ensuite la fonction
getpass, vous appelez en fait une fonction
spécifique à la plateforme que ce code a mis en place pour vous.
Vous n'avez pas à vous soucier de la plateforme sur laquelle votre
code est exécuté, appelez getpass, qui fera
ce qu'il faut.
Un bloc try...except peut avoir une
clause else, comme une instruction
if. Si aucune exception n'est déclenchée dans
le bloc try, la clause else
est exécutée à la suite. Dans ce cas, cela veut dire que l'import
from EasyDialogs import AskPassword a
fonctionné et donc nous assignons getpass à la
fonction AskPassword. Chacun des autres blocs
try...except a une clause
else similaire pour assigner
getpass à la bonne fonction lorsque nous
trouvons un import qui marche.
Pour en savoir plus sur le traitement des exceptions
La Python Library Reference documente le module traceback, qui fournit un accès de bas niveau aux attributs d'une exception après qu'elle ait été déclenchée.