3

Pythonで、コードをもう1つのブロックにラップする必要なしexceptに、ステートメントで同じ例外名のブロックを2回使用するにはどうすればよいですか?try/excepttry/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]

上記よりも優れた処理コードをいただければ幸いです。:)

ありがとう。

4

5 に答える 5

3

現在、あなたのユースケースに適した方法を見つけることはできませんが、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)
于 2012-05-07T06:58:57.203 に答える
2

これも実行できず、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_OPto NameError(オフセット17)が例外をキャッチし、2番目のそのような比較(オフセット36)の後にジャンプすることは明らかです。

于 2012-05-07T06:33:20.937 に答える
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]
于 2012-05-07T08:24:18.807 に答える
0

ブロックで発生した例外exceptは同じtry/exceptブロックで処理されないため、例は機能しません。たとえ可能であったとしても、最初の例では、except NameErrorそれ自体の内部から発生した例外を再度キャッチし、再び発生するNameErrorなど、永久に無限ループが発生するため、実際には無限ループが発生します。

この機能は仕様によるものです。例外を検査するが、例外を外部に発生させる例外ハンドラーを作成することは不可能であるためです。exceptブロックは、ブロック内からスローされた例外のみを処理しますtry。ブロック内からスローされた例外を処理する場合はexcept、そのブロックがブロック内にある必要がありtryます。

于 2012-05-07T07:23:07.840 に答える
0

PythonまたはSane言語での例外は、意図したとおりに機能することはありません。例外が発生するたびに、スタック/スコープをトレースバックする必要があります。現在のスコープで発生した例外は、スタック/スコープごとに1回だけ処理できます。これがそうであったと考えてください。すべてのスコープには単一の例外処理メカニズムがあり、一致について言及された順序として例外を単純にフィルタリングするフィルター関数があります。一致が発生した場合は、指定された例外ハンドラーに従って処理されます。例外が再スローまたは生成された場合は、次のスコープのすぐ近くにある次の例外処理メカニズムによって処理する必要があります。

例を見ると、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]
于 2012-05-07T06:36:00.150 に答える