103 votes

Quelle est une bonne façon de gérer les exceptions lors de la lecture d'un fichier en python ?

Je veux lire un fichier .csv en python.

  • Je ne sais pas si le fichier existe.
  • Ma solution actuelle est la suivante. Elle me semble peu soignée car les deux tests d'exception distincts sont maladroitement juxtaposés.

Y a-t-il un moyen plus joli de le faire ?

import csv    
fName = "aFile.csv"

try:
    with open(fName, 'rb') as f:
        reader = csv.reader(f)
        for row in reader:
            pass #do stuff here

except IOError:
    print "Could not read file:", fName

0 votes

Si un fichier inexistant n'est pas un cas d'erreur mais une circonstance probable, il faut alors vérifier et traiter son absence/non lisibilité explicitement avant (et en outre, à) la try pourrait en valoir la peine. Cela peut être fait avec os.path.exists(file) et os.access(file, os.R_OK) respectivement. Une telle vérification ne peut jamais être exempte d'une condition de course, mais la disparition de fichiers est rarement une circonstance normale ;)

2 votes

Les réponses à cette question devraient probablement être mises à jour afin d'inclure l'utilisation de l'outil d'évaluation de la qualité de l'eau. pathlib qui rend ce problème beaucoup plus facile, et devrait probablement être une pratique standard de Python (d'autant plus qu'il a également été rétroporté dans la version 2.7).

0 votes

Tandis que celui-ci attrape IOError il n'attrape pas csv.Error en raison du fait que le fichier n'est pas au format CSV lorsque Dialect.strict=True ou Error pour toute autre erreur (selon la documentation du paquet CSV), donc un essai externe, ou simplement la vérification de l'existence du fichier, puis un essai interne pour les exceptions CSV est probablement la bonne réponse.

74voto

Tim Pietzcker Points 146308

Que dites-vous de ça ?

try:
    f = open(fname, 'rb')
except OSError:
    print "Could not open/read file:", fname
    sys.exit()

with f:
    reader = csv.reader(f)
    for row in reader:
        pass #do stuff here

12 votes

Le seul problème, c'est que le fichier est ouvert en dehors de l'espace de travail de l'utilisateur. with bloc. Ainsi, si une exception se produit entre le try contenant l'appel à open et le with le fichier n'est pas fermé. Dans ce cas, où les choses sont très simples, ce n'est pas un problème évident, mais cela pourrait tout de même poser un danger lors du remaniement ou de toute autre modification du code. Ceci étant dit, je ne pense pas qu'il y ait une meilleure façon de faire (autre que la version originale).

3 votes

@intuited : C'est vrai. En fait, la réponse finale à l'OP est probablement juste : Non, la façon dont vous l'avez fait est la bonne.

1 votes

FileNotFoundError.mro() est [<class 'FileNotFoundError'>, <class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>] et IOError.mro() est [<class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>] . Que diriez-vous d'utiliser soit OSError ou Exception à la place ? ```

53voto

Josh Caswell Points 40397

Je crois que j'ai mal compris ce qui était demandé. En relisant, il semble que la réponse de Tim soit celle que vous souhaitez. Permettez-moi cependant d'ajouter ceci : si vous voulez attraper une exception provenant de open alors open doit être enveloppé dans un try . Si l'appel à open se trouve dans l'en-tête d'un with alors le with doit être dans un try pour attraper l'exception. Il n'y a aucun moyen de contourner cela.

Donc la réponse est soit : "La méthode de Tim" ou "Non, vous le faites correctement".


Réponse antérieure peu utile à laquelle tous les commentaires font référence :

import os

if os.path.exists(fName):
   with open(fName, 'rb') as f:
       try:
           # do stuff
       except : # whatever reader errors you care about
           # handle error

21voto

edW Points 27

Voici un exemple de lecture/écriture. Les instructions with assurent que l'instruction close() sera appelée par l'objet fichier, qu'une exception soit levée ou non. http://effbot.org/zone/python-with-statement.htm

import sys

fIn = 'symbolsIn.csv'
fOut = 'symbolsOut.csv'

try:
   with open(fIn, 'r') as f:
      file_content = f.read()
      print "read file " + fIn
   if not file_content:
      print "no data in file " + fIn
      file_content = "name,phone,address\n"
   with open(fOut, 'w') as dest:
      dest.write(file_content)
      print "wrote file " + fOut
except IOError as e:
   print "I/O error({0}): {1}".format(e.errno, e.strerror)
except: #handle other exceptions such as attribute errors
   print "Unexpected error:", sys.exc_info()[0]
print "done"

0 votes

Dans ce cas, l'erreur IOError est évidente, mais quand une exception générale se produira-t-elle du point de vue de la couverture du code ? Comment puis-je faire un scénario de test pour générer une exception générale.

2voto

obiwan2u Points 36

Pourquoi ne pas ajouter une clause "else" à l'exception et placer la déclaration "with" dans la section "else" ? Comme ceci :

try:
  f = open(fname, 'rb')
except FileNotFoundError:
    print(f"File {fname} not found.  Aborting")
    sys.exit(1)
except OSError:
    print(f"OS error occurred trying to open {fname}")
    sys.exit(1)
except Exception as err:
    print(f"Unexpected error opening {fname} is",repr(err))
    sys.exit(1)  # or replace this with "raise" ?
else:
  with f:
    reader = csv.reader(f)
    for row in reader:
        pass #do stuff here

Au lieu de sys.exit(), vous pourriez mettre 'raise' et faire remonter l'erreur dans la chaîne. Il serait peut-être préférable d'obtenir des informations système sur l'erreur à partir du gestionnaire d'erreur de niveau supérieur.

1voto

Lou Pendley Points 13
fname = 'filenotfound.txt'
try:
    f = open(fname, 'rb')
except FileNotFoundError:
    print("file {} does not exist".format(fname))

file filenotfound.txt does not exist

exception FileNotFoundError Lancée lorsqu'un fichier ou un répertoire est demandé mais n'existe pas. Correspond à errno ENOENT.

https://docs.python.org/3/library/exceptions.html
Cette exception n'existe pas dans Python 2.

1 votes

Bien que ce code puisse répondre à la question, le fait de fournir un contexte supplémentaire concernant la façon dont et/ou la raison pour laquelle il résout le problème améliorerait la valeur à long terme de la réponse.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X