web-dev-qa-db-fra.com

Pourquoi avons-nous besoin de la clause "finally" en Python?

Je ne sais pas pourquoi nous avons besoin de finally dans try...except...finally. À mon avis, ce bloc de code

try:
    run_code1()
except TypeError:
    run_code2()
other_code()

est la même chose avec celui-ci en utilisant finally:

try:
    run_code1()
except TypeError:
    run_code2()
finally:
    other_code()

Est-ce que je manque quelque chose?

243
RNA

Cela fait une différence si vous revenez plus tôt:

try:
    run_code1()
except TypeError:
    run_code2()
    return None   # The finally block is run before the method returns
finally:
    other_code()

Comparez à ceci:

try:
    run_code1()
except TypeError:
    run_code2()
    return None   

other_code()  # This doesn't get run if there's an exception.

Autres situations pouvant causer des différences:

  • Si une exception est levée à l'intérieur du bloc except.
  • Si une exception est levée dans run_code1() mais que ce n'est pas un TypeError.
  • Autres instructions de flux de contrôle telles que les instructions continue et break.
341
Mark Byers

Vous pouvez utiliser finally pour vous assurer que les fichiers ou les ressources sont fermés ou publiés, qu’une exception se produise ou non , même si vous ne détectez pas l’exception. (Ou si vous n'acceptez pas cette exception spécifique .)

myfile = open("test.txt", "w")

try:
    myfile.write("the Answer is: ")
    myfile.write(42)   # raises TypeError, which will be propagated to caller
finally:
    myfile.close()     # will be executed before TypeError is propagated

Dans cet exemple, vous feriez mieux d'utiliser l'instruction with, mais ce type de structure peut être utilisé pour d'autres types de ressources.

Quelques années plus tard, j'ai écrit n article de blog à propos d'un abus de finally que les lecteurs pourraient trouver amusant.

70
kindall

Ils ne sont pas équivalents. Enfin, le code est exécuté quoi qu'il arrive. C'est utile pour le code de nettoyage à exécuter.

22
Antimony

Pour ajouter aux autres réponses ci-dessus, la clause finally s'exécute de n'importe quelle façon, tandis que la clause else ne s'exécute que si une exception n'a pas été déclenchée.

Par exemple, l'écriture dans un fichier sans exception produira les résultats suivants:

file = open('test.txt', 'w')

try:
    file.write("Testing.")
    print("Writing to file.")
except IOError:
    print("Could not write to file.")
else:
    print("Write successful.")
finally:
    file.close()
    print("File closed.")

OUTPUT:

Writing to file.
Write successful.
File closed.

S'il existe une exception, le code générera ce qui suit, (notez qu'une erreur délibérée est provoquée par le fait de garder le fichier en lecture seule.

file = open('test.txt', 'r')

try:
    file.write("Testing.")
    print("Writing to file.")
except IOError:
    print("Could not write to file.")
else:
    print("Write successful.")
finally:
    file.close()
    print("File closed.")

OUTPUT:

Could not write to file.
File closed.

Nous pouvons voir que la clause finally s'exécute indépendamment d'une exception. J'espère que cela t'aides.

12
captainblack

Les blocs de code ne sont pas équivalents. La clause finally sera également exécutée si run_code1() lève une exception autre que TypeError, ou si run_code2() lève une exception, alors que other_code() dans la première version ne le serait pas. ne pas être exécuté dans ces cas.

7
Sven Marnach

Dans votre premier exemple, que se passe-t-il si run_code1() lève une exception qui n'est pas TypeError? ... other_code() ne sera pas exécuté.

Comparez cela avec la version finally:: other_code() est exécuté même si une exception est déclenchée.

7
mhawke

Comme expliqué dans la documentation , la clause finally est destinée à définir des actions de nettoyage qui doivent être exécutées dans toutes les circonstances .

Si finally est présent, il spécifie un gestionnaire de "nettoyage". La clause try est exécutée, y compris les clauses except et else. Si une exception se produit dans l'une des clauses et n'est pas gérée, l'exception est temporairement enregistrée. La clause finally est exécutée. S'il existe une exception enregistrée, elle est à nouveau levée à la fin de la clause finally.

Un exemple:

>>> def divide(x, y):
...     try:
...         result = x / y
...     except ZeroDivisionError:
...         print("division by zero!")
...     else:
...         print("result is", result)
...     finally:
...         print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'

Comme vous pouvez le constater, la clause finally est exécutée dans tous les cas. La TypeError déclenchée en divisant deux chaînes n'est pas gérée par la clause except, elle est donc renouvelée une fois que la clause finally a été exécutée.

Dans les applications réelles, la clause finally est utile pour libérer des ressources externes (telles que des fichiers ou des connexions réseau), que la ressource ait été utilisée ou non.

3
Eugene Yarmash

Enfin, peut également être utilisé lorsque vous souhaitez exécuter du code "optionnel" avant d’exécuter le code pour votre travail principal et que ce code facultatif peut échouer pour diverses raisons.

Dans l'exemple suivant, nous ne savons pas exactement quel type d'exception store_some_debug_info peut générer.

Nous pourrions courir:

try:
  store_some_debug_info()
except Exception:
  pass
do_something_really_important() 

Cependant, la plupart des linters se plaindront d’avoir attrapé une exception trop vague. De plus, comme nous choisissons de n'utiliser que pass pour les erreurs, le bloc except n'ajoute pas vraiment de valeur.

try:
  store_some_debug_info()
finally:
  do_something_really_important()     

Le code ci-dessus a le même effet que le 1er bloc de code mais est plus concis.

2
Brad Johnson

finally sert à définir "actions de nettoyage". La clause finally est exécutée dans tous les événements avant de quitter l'instruction try, qu'une exception (même si vous ne la gérez pas) se soit produite ou non.

Je soutiens l'exemple de @ Byers.

2
kakhkAtion

Exemple parfait est comme ci-dessous:

try:
    #x = Hello + 20
    x = 10 + 20 
except:
    print 'I am in except block'
    x = 20 + 30
else:
    print 'I am in else block'
    x += 1
finally:
    print 'Finally x = %s' %(x)
2
Abhijit Sahu

L'utilisation professionnelle de Delphi pendant quelques années m'a appris à protéger mes routines de nettoyage. Delphi impose finalement d’utiliser finalement pour nettoyer toutes les ressources créées avant le bloc try, de peur que vous ne provoquiez une fuite de mémoire. C'est également comme cela que Java, Python et Ruby fonctionnent.

resource = create_resource
try:
  use resource
finally:
  resource.cleanup

et les ressources seront nettoyées indépendamment de ce que vous faites entre essayer et enfin. En outre, il ne sera pas nettoyé si l'exécution n'atteint jamais le bloc try. (c'est-à-dire que create_resource lui-même lève une exception). Cela rend votre code "exception sûre".

Quant à la raison pour laquelle vous avez réellement besoin d’un blocage final, toutes les langues n’en ont pas besoin. En C++, vous avez automatiquement appelé les destructeurs qui appliquent le nettoyage lorsqu'une exception déroule la pile. Je pense que c'est une avancée dans la direction d'un code plus propre par rapport à essayer ... enfin les langues.

{    
  type object1;
  smart_pointer<type> object1(new type());
} // destructors are automagically called here in LIFO order so no finally required.
2
nurettin

Un bloc try n'a qu'une seule clause obligatoire: l'instruction try. Les clauses except, else et finally sont facultatives et basées sur les préférences de l'utilisateur.

enfin: Avant que Python ne quitte l'instruction try, il exécutera le code du bloc finally dans toutes les conditions, même s'il met fin au programme. Par exemple, si Python a rencontré une erreur lors de l'exécution du code dans le bloc except ou else, le dernier bloc sera toujours exécuté avant l'arrêt du programme.

0