Search code examples
pythonexceptionsyntaxdjango-orm

"except" statement with same exception class as parameter twice


In Python, how can I use except block with same exception name twice in try/except statements without need to wrap code into one more try/except block?

Simple example (here each call of pages.get may raise the exception):

try:
    page = pages.get(lang=lang)
except Page.DoesNotExist:
    if not lang == default_lang:
        page = pages.get(lang=default_lang)
    else:
        raise Page.DoesNotExist
except Page.DoesNotExist:
    page = pages[0]

For now, in my Django app I do handling like this (but I don't want "extra" try block here):

try:
    try:
        page = pages.get(lang=lang)
    except Page.DoesNotExist:
        if not lang == default_lang:
            page = pages.get(lang=default_lang)
        else:
            raise Page.DoesNotExist
except Page.DoesNotExist:
    page = pages[0]

Any handling code better than above is appreciated! :)

Thanks.


Solution

  • You can't do this either and expect the elif to execute:

    if foo == bar:
      # do "if"
    elif foo == bar:
      # do "elif"
    

    And there's no reason to do this, really. Same for your except concern.

    Here's the disassembled Python bytecode of your first code snippet:

     13           0 SETUP_EXCEPT            10 (to 13)
    
     14           3 LOAD_GLOBAL              0 (NameError)
                  6 RAISE_VARARGS            1
                  9 POP_BLOCK           
                 10 JUMP_FORWARD            44 (to 57)
    
     15     >>   13 DUP_TOP             
                 14 LOAD_GLOBAL              0 (NameError)
                 17 COMPARE_OP              10 (exception match)
                 20 POP_JUMP_IF_FALSE       35
                 23 POP_TOP             
                 24 POP_TOP             
                 25 POP_TOP             
    
     16          26 LOAD_GLOBAL              0 (NameError)
                 29 RAISE_VARARGS            1
                 32 JUMP_FORWARD            22 (to 57)
    
     17     >>   35 DUP_TOP             
                 36 LOAD_GLOBAL              0 (NameError)
                 39 COMPARE_OP              10 (exception match)
                 42 POP_JUMP_IF_FALSE       56
                 45 POP_TOP             
                 46 POP_TOP             
                 47 POP_TOP             
    
     18          48 LOAD_CONST               1 (1)
                 51 PRINT_ITEM          
                 52 PRINT_NEWLINE       
                 53 JUMP_FORWARD             1 (to 57)
            >>   56 END_FINALLY         
            >>   57 LOAD_CONST               0 (None)
                 60 RETURN_VALUE        
    

    It's obvious that the first COMPARE_OP to NameError (at offset 17) will catch the exception and jump to after the second such comparison (at offset 36).