Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"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.

like image 626
neoascetic Avatar asked Nov 30 '25 22:11

neoascetic


2 Answers

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).

like image 102
Eli Bendersky Avatar answered Dec 03 '25 11:12

Eli Bendersky


Though, I can't currently figure out a better way for your use-case, Python's try/except statement has some extra features:

try:
  pass
  # run your code
except:
  pass
  # run your error handling, etc.. 
else:
  pass
  # is run whenever an exception didn't happen
finally:
  pass
  # will be executed always (good for cleaning up)
like image 45
plaes Avatar answered Dec 03 '25 12:12

plaes



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!