“except”语句具有相同的异常类作为参数两次

时间:2012-05-07 06:27:08

标签: python exception syntax django-orm

在Python中,如何在except语句中两次使用具有相同异常名称的try/except块,而无需将代码再包装到另一个try/except块中?

简单示例(此处 pages.get的每次调用都可能引发异常):

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]

现在,在我的Django应用程序中,我会像这样处理(但我不想在这里“额外”try阻止):

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]

任何比上述更好的处理代码表示赞赏! :)

感谢。

5 个答案:

答案 0 :(得分:1)

你也不能这样做,并期望elif执行:

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

并且没有理由这样做,真的。您的except问题也是如此。

这是您的第一个代码段的反汇编Python字节码:

 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        

很明显,第一个COMPARE_OPNameError(在偏移17处)将捕获异常并跳转到第二个这样的比较之后(在偏移量36处)。

答案 1 :(得分:1)

我建议您创建一个函数来为您获取页面,例如。像这样:

def get_page(language):
    if language == default_lang:
        lang_list = [language]
    else:
        lang_list = [language, default_lang]

    for lang in lang_list:
        try:
            return pages.get(lang=lang)
        except Page.DoesNotExist:
            pass

    return pages[0]

答案 2 :(得分:0)

Python中的异常或任何Sane语言永远不会像你想要的那样工作。每次引发异常时,它都应该追溯堆栈/范围。在当前作用域中引发的任何异常每个堆栈/作用域只能处理一次。 认为这是,每个范围都有一个异常处理机制,带有一个过滤功能,它只是根据匹配所提到的顺序过滤异常。如果匹配发生,则按照指定的异常处理程序进行处理。如果重新抛出或生成任何异常,则应由下一个异常处理机制处理,该机制只是下一个范围的直接处理。

看一下这个例子,我想知道你为什么要通过引发另一个异常而不是在else块中处理它来使事实复杂化

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

答案 3 :(得分:0)

虽然,我目前无法为您的用例找到更好的方法,但Python的try/except语句还有一些额外的功能:

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)

答案 4 :(得分:0)

except块中引发的异常不会由同一try / except块处理,因此您的示例无效。即使你可以,你的例子实际上会产生一个无限循环,因为第一个except NameError只会再次捕获从内部引发的异常,并再次引发NameError,依此类推。 / p>

此功能是设计使然,因为否则无法编写检查异常但随后向外引发异常的异常处理程序。 except块仅处理从try块中抛出的异常。如果要处理从except块中抛出的异常,则该块需要位于try块内。