web-dev-qa-db-fra.com

python essayer: sauf: enfin

# Open new file to write
file = None
try:
    file = open(filePath, 'w')
except IOError:
    msg = ("Unable to create file on disk.")
    file.close()
    return
finally:
    file.write("Hello World!")
    file.close()

Le code ci-dessus est extrait d'une fonction. L'un des systèmes de l'utilisateur signale une erreur en ligne:

file.write("Hello World!")

erreur:

AttributeError: 'NoneType' object has no attribute 'write'

La question est la suivante: si python n’est pas parvenu à ouvrir un fichier donné, le bloc «sauf» s’exécute et doit renvoyer, mais le contrôle est transféré sur la ligne qui génère une erreur donnée. La valeur de la variable 'file' est 'None'.

Des pointeurs?

35
user354051

Vous ne devriez pas écrire dans le fichier dans le bloc finally car les exceptions déclenchées ne seront pas interceptées par le bloc except.

Le bloc except s'exécute s'il existe une exception déclenchée par le bloc try. Le finally block always exécute quoi qu'il arrive.

En outre, il ne devrait pas être nécessaire d’initialiser la variable file à none.

L'utilisation de return dans le bloc except n'ignorera pas le bloc finally. Par nature, il ne peut pas être ignoré. C’est pourquoi vous souhaitez y insérer votre code de "nettoyage" (c’est-à-dire la fermeture de fichiers).

Donc, si vous voulez utiliser essayer: sauf: enfin, vous devriez faire quelque chose comme ceci:

try:
    f = open("file", "w")
    try:
        f.write('Hello World!')
    finally:
        f.close()
except IOError:
    print 'oops!'

Pour ce faire, utilisez l’énoncé with:

try:
    with open("output", "w") as outfile:
        outfile.write('Hello World')
except IOError:
    print 'oops!'
84
Acorn

Si le fichier n'est pas ouvert, la ligne file = open(filePath, 'w') échoue et rien n'est affecté à file.

Ensuite, la clause except s'exécute, mais rien n'est dans le fichier, donc file.close() échoue.

La clause finally est toujours exécutée, même s'il y a eu une exception. Et puisque file est toujours None, vous obtenez une autre exception.

Vous voulez une clause else au lieu de finally pour les événements qui ne surviennent que s'il n'y a pas d'exception.

    try:
        file = open(filePath, 'w')
    except IOError:
        msg = "Unable to create file on disk."
        return
    else:
        file.write("Hello World!")
        file.close()

Pourquoi la else? Les docs Python dire: 

L’utilisation de la clause else est préférable à l’ajout de code supplémentaire à la clause try car elle évite d’attraper accidentellement une exception qui n’a pas été générée par le code protégé par l’instruction try ... except.

En d'autres termes, cela n'acceptera pas une IOError parmi les appels write ou close. Ce qui est bien, car alors la raison n'aurait pas été «Impossible de créer un fichier sur le disque». Cela aurait été une erreur différente, une erreur pour laquelle votre code n'a pas été préparé. C'est une bonne idée de ne pas essayer de gérer de telles erreurs.

27
Petr Viktorin

Voici la solution la plus directe à votre problème. J'utilise l'idiome de la vérification de file_obj != None dans le bloc finally

Soit dit en passant, vous devez savoir que file est un nom de classe Python. Vous devez donc choisir un nom de variable différent.

file = None
try:
    file = open(filePath, 'w')
except IOError:
    msg = ("Unable to create file on disk.")
    file.close()
    return
finally:
    if file != None:
        file.write("Hello World!")
        file.close()
1

sauf que ne s’exécute pas (car type est IOError), c’est la dernière partie qui génère une autre erreur de type AttributeError car file = None.

1
TigOldBitties

Vous pouvez faire quelque chose comme ça:

try:
    do_some_stuff()
finally:
    cleanup_stuff()
1
user5578789

enfin, il est toujours appelé à la fin, même si une exception se produit. Vous pouvez vous en servir pour vous assurer que les ressources ouvertes sont fermées (par exemple, une connexion à une base de données, un fichier, etc.).

Je pense que vous avez mal compris la sémantique.

Votre logique doit être dans le "try", vous devez gérer les exceptions dans le bloc "except", et "finally" s'exécute quelle que soit la façon dont votre méthode se termine, utilisez-la pour nettoyer.

0
pcalcao