Can I get the exception from the finally block in python?

前端 未结 4 873
夕颜
夕颜 2020-12-04 23:56

I have a try/finally clause in my script. Is it possible to get the exact error message from within the finally clause?

相关标签:
4条回答
  • 2020-12-05 00:20

    You'll want to do that in the except clause, not the finally.

    Refer to: http://www.doughellmann.com/articles/Python-Exception-Handling/

    0 讨论(0)
  • 2020-12-05 00:21

    The finally block will be executed regardless of whether an exception was thrown or not, so as Josh points out, you very likely don't want to be handling it there.

    If you really do need the value of an exception that was raised, then you should catch the exception in an except block, and either handle it appropriately or re-raise it, and then use that value in the finally block -- with the expectation that it may never have been set, if there was no exception raised during execution.

    import sys
    
    exception_name = exception_value = None
    
    try:
        # do stuff
    except Exception, e:
        exception_name, exception_value = sys.exc_info()[:2]
        raise   # or don't -- it's up to you
    finally:
        # do something with exception_name and exception_value
        # but remember that they might still be none
    
    0 讨论(0)
  • 2020-12-05 00:21

    Actually, other answers are bit vague. So, let me clarify it. You can always invoke sys.exc_info() from finally block. However, its output will vary depending whether exception has been actually raised.

    import sys
    
    def f(i):
    
        try:
            if i == 1:
                raise Exception
        except Exception as e:
            print "except -> " + str(sys.exc_info())
        finally:
            print "finally -> " + str(sys.exc_info())
    
    f(0)
    f(1)
    
    >>> 
    finally -> (None, None, None)
    except -> (<type 'exceptions.Exception'>, Exception(), <traceback object at 0x029438F0>)
    finally -> (<type 'exceptions.Exception'>, Exception(), <traceback object at 0x029438F0>)
    

    Thus, you can always know in finally block, whether exception was raised, if it's first level function. But sys.exc_info() will behave differently when length of call stack exceeds 1, as shown in below example. For more information, refer to How sys.exc_info() works?

    import sys
    
    def f(i):
    
        try:
            if i == 1:
                raise Exception
        except Exception as e:
            print "except -> " + str(sys.exc_info())
        finally:
            print "finally -> " + str(sys.exc_info())
    
    def f1(i):
        if i == 0:
            try:
                raise Exception('abc')
            except Exception as e:
                pass
    
        f(i)
    
    f1(0)
    f1(1)
    
    >>> 
    finally -> (<type 'exceptions.Exception'>, Exception('abc',), <traceback object at 0x02A33940>)
    except -> (<type 'exceptions.Exception'>, Exception(), <traceback object at 0x02A33990>)
    finally -> (<type 'exceptions.Exception'>, Exception(), <traceback object at 0x02A33990>)
    

    I hope, it makes things bit clearer.

    0 讨论(0)
  • 2020-12-05 00:29

    No, at finally time sys.exc_info is all-None, whether there has been an exception or not. Use:

    try:
      whatever
    except:
      here sys.exc_info is valid
      to re-raise the exception, use a bare `raise`
    else:
      here you know there was no exception
    finally:
      and here you can do exception-independent finalization
    
    0 讨论(0)
提交回复
热议问题