without - try except python 3




"Enfin" est-il toujours exécuté en Python? (4)

"Garanti" est un mot beaucoup plus fort que toute implémentation de mérite finally . Ce qui est garanti, c’est que si l’exécution découle de l’ try finally - construction finale, elle passera par le finally . Ce qui n’est pas garanti, c’est que l’exécution découlera de l’ try - finally .

  • Un finally dans un générateur ou une coroutine asynchrone peut ne jamais s'exécuter , si l'objet ne s'exécute jamais jusqu'à la conclusion. Il y a beaucoup de manières qui pourraient arriver; en voici un:

    def gen(text):
        try:
            for line in text:
                try:
                    yield int(line)
                except:
                    # Ignore blank lines - but catch too much!
                    pass
        finally:
            print('Doing important cleanup')
    
    text = ['1', '', '2', '', '3']
    
    if any(n > 1 for n in gen(text)):
        print('Found a number')
    
    print('Oops, no cleanup.')

    Notez que cet exemple est un peu délicat: lorsque le générateur est mal ordonné, Python essaie d’exécuter le bloc finally en lançant une exception GeneratorExit , mais dans ce cas, nous interceptons cette exception puis nous yield , ce à quoi Python affiche un avertissement (" générateur ignoré GeneratorExit ") et abandonne. Voir PEP 342 (Coroutines via Enhanced Generators) pour plus de détails.

    Un générateur ou une coroutine peut ne pas être exécuté jusqu’à la conclusion si l’objet n’est jamais soumis à la GC (oui, c’est possible, même dans CPython), ou si un async with await dans __aexit__ , ou si l’ await ou yield s dans un bloc finally . Cette liste n'est pas exhaustive.

  • finally un thread de démon peut ne jamais s'exécuter si tous les threads non-démon se ferment en premier

  • os._exit interrompt immédiatement le processus sans exécuter les blocs.

  • os.fork peut provoquer finally blocs s'exécutent deux fois . En plus des problèmes normaux que vous attendez de ce qui se passe deux fois, cela pourrait entraîner des conflits d'accès simultanés (plantages, blocages, ...) si l'accès aux ressources partagées n'est pas correctement synchronisé .

    Étant donné que le multiprocessing utilise fork-without-exec pour créer des processus de travail lors de l'utilisation de la méthode de démarrage fork (la valeur par défaut sous Unix), puis appelle os._exit dans le travailleur une fois le travail du travailleur terminé, une interaction multiprocessing traitement peut s'avérer problématique ( example ).

  • Une erreur de segmentation au niveau C empêchera finally blocs de s'exécuter.
  • kill -SIGKILL empêchera finally blocs de fonctionner. SIGTERM et SIGHUP empêcheront finally blocs de fonctionner à moins d’installer un gestionnaire pour contrôler vous-même l’arrêt; Par défaut, Python ne gère pas SIGTERM ni SIGHUP .
  • Une exception dans finally peut empêcher le nettoyage de se terminer. Un cas particulièrement remarquable est celui où l'utilisateur appuie sur Control-C au moment où nous commençons à exécuter le bloc finally . Python lèvera un KeyboardInterrupt et sautera toutes les lignes du contenu du bloc finally . ( KeyboardInterrupt code de sécurité KeyboardInterrupt est très difficile à écrire).
  • Si l'ordinateur tombe en panne, ou s'il passe en veille et ne se réveille pas, les blocs ne fonctionneront pas.

Le bloc finally n'est pas un système de transaction; il ne fournit aucune garantie d'atomicité ni rien de ce genre. Certains de ces exemples peuvent sembler évidents, mais il est facile d’oublier que de telles choses peuvent se produire et s’en remettre finally à trop.

Pour tout bloc try-finally possible en Python, est-il garanti que le bloc finally sera toujours exécuté?

Par exemple, supposons que je retourne dans un bloc except :

try:
    1/0
except ZeroDivisionError:
    return
finally:
    print("Does this code run?")

Ou peut-être que je relance une Exception :

try:
    1/0
except ZeroDivisionError:
    raise
finally:
    print("What about this code?")

Les tests montrent que les exemples ci-dessus sont finally exécutés, mais j'imagine qu'il existe d'autres scénarios auxquels je n'ai pas pensé.

Existe-t-il des scénarios dans lesquels l'exécution d'un bloc finally peut échouer en Python?


Eh bien oui et non.

Ce qui est garanti, c’est que Python essaiera toujours d’exécuter le bloc finally. Dans le cas où vous revenez du bloc ou que vous levez une exception non capturée, le bloc finally est exécuté juste avant de renvoyer ou de lever l'exception.

(ce que vous auriez pu contrôler vous-même en exécutant simplement le code dans votre question)

Le seul cas où je peux imaginer où le bloc final ne sera pas exécuté est celui où l'interpréteur Python se bloque, par exemple dans le code C ou en raison d'une panne de courant.


Oui. Enfin toujours gagne.

La seule façon de le vaincre est d’arrêter l’exécution avant d’avoir une chance de s’exécuter (par exemple, bloquer l’interprète, éteindre votre ordinateur, suspendre un générateur pour toujours).

J'imagine qu'il y a d'autres scénarios auxquels je n'ai pas pensé.

Voici un couple de plus que vous n'auriez peut-être pas pensé:

def foo():
    # finally always wins
    try:
        return 1
    finally:
        return 2

def bar():
    # even if he has to eat an unhandled exception, finally wins
    try:
        raise Exception('boom')
    finally:
        return 'no boom'

Selon la façon dont vous avez quitté l'interprète, vous pouvez parfois "annuler" enfin, mais pas comme ceci:

>>> import sys
>>> try:
...     sys.exit()
... finally:
...     print('finally wins!')
... 
finally wins!
$

Utiliser l' os._exit précaire (à mon avis, cela tombe sous "crash l'interprète"):

>>> import os
>>> try:
...     os._exit(1)
... finally:
...     print('finally!')
... 
$

J'exécute actuellement ce code pour tester si finalement sera toujours exécuté après la mort de l'univers par la chaleur:

try:
    while True:
       sleep(1)
finally:
    print('done')

Cependant, j'attends toujours le résultat, alors revenez plus tard.


Pour vraiment comprendre son fonctionnement, exécutez ces deux exemples:

  • try:
        1
    except:
        print 'except'
    finally:
        print 'finally'

    va sortir

    enfin

  • try:
        1/0
    except:
        print 'except'
    finally:
        print 'finally'

    va sortir

    sauf
    enfin







finally