簡體   English   中英

嵌套 try-except 塊會導致代碼過度縮進

[英]Nesting try-except blocks leads to overly indented code

我在編寫 Python 代碼時遇到了一個相當哲學的問題。 通常,使用盡可能多的try-except-else塊來處理所有可預期的情況被認為是一種很好的風格。 但我發現這種方法有時會導致不必要的多級縮進,這使得很難將行數保持在 80 以下,並暗示代碼中不存在層次結構。 我覺得我缺少某種“GOTO”語句或類似的跳轉來應對這個問題。 因此,我想知道我是否缺少一些編碼風格、Python 語句或模式來改進我的 Python 代碼。

我舉一個更具體的例子。 讓我們認為我正在定義一個函數,並且我在一個循環中,在那里各種事情可能會出錯。 每件事都足以使循環中的其余代碼可跳過,我通常以類似於以下方式continue跳過這些代碼:

def mu_func()
    failed = False
    for i in range(100):
        try:
            pass
            # we try something that might raise an exception
        except:
            print("something went wrong by reason #1")
            failed = True
            continue
        try:
            pass
            # we try something that might raise an exception
        except:
            print("something went wrong by reason #2")
            failed = True
            continue
        try:
            pass
            # we try something that might raise an exception
        except:
            print("something went wrong by reason #3")
            failed = True
    # some cleanup code at the end of the function
    # that depends on the errors raised
    return failed

這里要注意的重要一點是,由於我們處於循環中,如果引發任何異常, continue語句使我不必使用else語句跳過其余代碼。 因此,縮進級別不會繼續增長。 另請注意,我不能只是退出異常處理,因為我需要在從函數返回之前進行一些清理。

現在注意當我們不在循環中時會發生什么:

def mu_func()
    failed = False
    try:
        pass
        # we try something that might raise an exception
    except:
        print("something went wrong by reason #1")
        failed = True
    else:
        try:
            pass
            # we try something that might raise an exception
        except:
            print("something went wrong by reason #2")
            failed = True
        else:
            try:
                pass
                # we try something that might raise an exception
            except:
                print("something went wrong by reason #3")
               failed = True
    # some cleanup code at the end of the function
    # that depends on the errors raised
    return failed

看到不同? 如果想在引發任何異常后跳過其余代碼,我必須將下面的所有內容放入else語句中,從那時起,它會略微增加縮進級別。 這不僅會導致難以將行數保持在 80 個字符以下的煩人代碼。 最糟糕的是,這些嵌套的try-except-else塊暗示了代碼中的某種層次結構,這是人為的。 所有例外都同等重要。 在第一個示例中可以很容易地理解這一點,其中可以很好地交換try-except塊的順序,而無需觸及縮進且不影響功能。

是否有 Python 語句或模式允許我在處理異常后跳過其余代碼,從而使我不必添加越來越多的縮進級別? 我是否誤用了else語句? 我很想把所有東西都放在一個簡單的 1 次迭代循環中,這樣我就可以訪問continue語句來執行跳轉到我遺漏的塊語句的末尾

一種方法可能是用try-except塊包裝 for 循環:

def mu_func():
    try:
        for i in range(100):
            # we try something that might raise an exception
            action_1()
            print("action #1 succeeds")

            action_2()
            print("action #2 succeeds")

            action_3()
            print("action #3 succeeds")

    except:
        print("something went wrong!")
        failed = True

    else:
        failed = False

    return failed

如果你的 for 循環中有其他邏輯,我建議只包裝可能引發異常的邏輯:

def mu_func():
    for i in range(100):
        try:
            # we try something that might raise an exception
            action_1()
            print("action #1 succeeds")

            action_2()
            print("action #2 succeeds")

            action_3()
            print("action #3 succeeds")

        except:
            print("something went wrong!")
            failed = True
            break

        # here we might do other stuff in the loop
        ...
    
    else:
        failed = False

    return failed

怎么用:

def mu_func()
    failed = False
    try:
        pass
        # we try something that might raise an exception
    except ExceptionClass1():
        print("something went wrong by reason #1")
        failed = True
    except ExceptionClass2():
        print("something went wrong by reason #2")
        failed = True
    except ExceptionClass3():
        print("something went wrong by reason #3")
        failed = True
    except ExceptionClass4():
        print("something went wrong by reason #4")
        failed = True
    return failed

我找到了 2 個解決問題的方法。 我會將它們張貼在這里以激發進一步的討論或在我的情況下幫助其他人。 不過,我不會將此標記為答案,因為我發現它們更像是一種解決方法而不是正確的解決方案。 它們在某種程度上是基於這個問題的答案(我認為它接受的答案不能解決問題)。

使用虛擬循環的解決方案

這里的想法是偽造一個循環來訪問允許您跳轉到函數末尾的continue語句。

def mu_func()
    failed = False
    for _ in range(1):
        try:
            pass
            # we try something that might raise an exception
        except Exception1:
            print("something went wrong by reason #1")
            failed = True
            continue
        try:
            pass
            # we try something that might raise an exception
        except Exception2:
            print("something went wrong by reason #2")
            failed = True
            continue
        try:
            pass
            # we try something that might raise an exception
        except Exception3:
            print("something went wrong by reason #3")
            failed = True
    # some cleanup code at the end of the function
    # that must be executed before leaving
    return failed

這個解決方案有效,但它非常丑陋,因為以一種創造性的方式使用 for 循環,這顯然不是它的設計目的。

使用2級異常處理的解決方案

這里的想法是定義和使用通用異常,並使用它來轉換異常類型以表示出現問題(但它已經被處理),然后基本上將執行流程發送到最后。

class MyException(Exception):
    pass

def mu_func()
    failed = False
    try:
        try:
            pass
            # we try something that might raise an exception
        except Exception1:
            print("something went wrong by reason #1")
            raise MyException
        try:
            pass
            # we try something that might raise an exception
        except Exception2:
            print("something went wrong by reason #2")
            raise MyException
        try:
            pass
            # we try something that might raise an exception
        except Exception3:
            print("something went wrong by reason #3")
            raise MyException
    except MyException:
        failed = True
    # some cleanup code at the end of the function
    # that depends on the errors raised
    return failed

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM