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?
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:
run_code1()
mais que ce n'est pas un TypeError
.continue
et break
.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.
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.
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.
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.
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.
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 clausetry
est exécutée, y compris les clausesexcept
etelse
. Si une exception se produit dans l'une des clauses et n'est pas gérée, l'exception est temporairement enregistrée. La clausefinally
est exécutée. S'il existe une exception enregistrée, elle est à nouveau levée à la fin de la clausefinally
.
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.
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.
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.
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)
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.
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.