neoascetic neoascetic - 7 months ago 11
Python Question

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

Answer

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