4 votes

try/finally - que fait Python à l'espace de nom local lors d'une exception ?

Il ne s'agit pas d'un duplicata des divers documents de l'UE. pourquoi une exception est finalement supprimée questions.

Au lieu de cela, je trouve que finally Les variables locales de l'utilisateur sont inattendues, mais seulement dans le cas d'une exception. Dans ce cas, l'exception disparaît.

(Ceci est sous Python 3.8)

def test(divisor):
    print(f"\n\ntest({divisor=})")
    exc = None  #  always assigned!
    foo = 1

    print(f"  ante.{exc=}")

    try:
        _ = 1 / divisor
        print(f"  post.{exc=}")

    except (Exception,) as exc: 
        print(f"  except.{exc=}")
    else:
        print(f"  else.{exc=}")
    finally:
        print(f"  finally:{locals()=}")

        #at this point, it should be either None 
        #whatever was caught in the except clause
        print(f"  finally.{exc=}")

test(1)

test(0)

Sortie en cas de succès - comme prévu :

test(divisor=1)
  ante.exc=None
  post.exc=None
  else.exc=None
  finally:locals()={'divisor': 1, 'exc': None, 'foo': 1, '_': 1.0}
  finally.exc=None

Sur une exception - UnboundLocalError

Il semble que l'espace de nom local ait exc supprimé et cela provoque une erreur UnboundLocalError.

Je m'attendrais à ce qu'il y ait une ZeroDivisionError. Tout au plus, si except définissait une portée locale pour une raison quelconque, il pourrait toujours être None . Mais c'est parti.

comme si del locals()["exc"] avait eu lieu.

test(divisor=0)
  ante.exc=None
  except.exc=ZeroDivisionError('division by zero')
  finally:locals()={'divisor': 0, 'foo': 1}
Traceback (most recent call last):
  File "test_195_finally.py:27", in <module>
    test(0)
  File "test_195_finally.py:23", in test
    print(f"  finally.{exc=}")
UnboundLocalError: local variable 'exc' referenced before assignment

Reliure exc à une autre variable montre que cette autre variable est bien vivante.

    except (Exception,) as exc: 
        exc2=exc

  finally:locals()={'divisor': 0, 'foo': 1, 'exc2': ZeroDivisionError('division by zero')}

3voto

Adrian Points 8690

Citant ce fil à propos du même problème dans le Python bug tracker, c'est le comportement attendu

[Cela se produit parce que nous devons nettoyer la variable d'exception à l'extérieur de la fonction except pour éviter les cycles de référence. Si vous avez besoin de la variable plus tard, vous devez faire une affectation [ ].

... qui est aussi documenté :

Lorsqu'une exception a été attribuée à l'aide de as target il est effacé à la fin de la clause except.

Ainsi, pour conserver la référence de l'objet, vous devez la stocker dans une variable nommée différemment à l'intérieur de l'objet except bloc.

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