首頁 > 軟體

Python例外處理如何才能寫得優雅(retrying模組)

2022-03-23 13:02:15

前言

在寫程式時,我們會經常碰到程式出現異常,這時候我們就不得不處理這些異常,以保證程式的健壯性。

處理異常的版本有以下幾種,你通常的做法是哪種?

不負責任版本

這種情況下,不作任何處理,任由程式報錯,從而導致程式中斷。

針對簡單的程式,這樣做沒什麼問題,大不了我遇到問題之後把問題解決,然後重新執行。但是如果是複雜的系統就會很麻煩了,可能你一個異常阻塞了系統的執行,帶來災難性的後果。

簡單處理版本

簡單處理版本,就是加上異常捕獲,在發生異常時記錄紀錄檔,時候可以通過紀錄檔來定位異常。

def do_something():
    pass
def log_error(xxx):
    pass

try:
   do_something()
except:
    log_error(xxxx)

改進處理版本

對於簡單處理版本做了改進,增加重試次數。這個在爬蟲程式中比較常見,第一次請求超時,可能過一會再請求就成功了,所以重試幾次可能會消除異常。

attempts = 0
success = False
while attempts < 3 and not success:
    try:
        do_something()
        success = True
    except:
        attempts += 1
        if attempts == 3:
            break

但是這樣做仍然不夠優雅,你可能要在很多地方去寫這種重試的寫死,程式看起來亂糟糟的。

今天就給大家介紹一個第三方模組 —— retrying。它是對程式中異常重試的一種優雅的解決方案。

安裝與使用

安裝

安裝命令還是那麼平淡無奇:

pip install retrying

使用

下面給大家介紹一下這個裝飾函數有哪些可以使用的引數。

生命不息,奮鬥不止

retrying 提供一個裝飾器函數 retry,被裝飾的函數會在執行失敗的情況下重新執行,預設一直報錯就一直重試。

import random
from retrying import retry

@retry
def do_something_unreliable():
    if random.randint(0, 10) > 1:
        print("just have a test")
        raise IOError("raise exception!")
    else:
        return "good job!"

print(do_something_unreliable())

執行這個程式,大家可以看到每次列印“just have a test”這句話的次數都不一樣。這是由於我們程式中只要隨機整數大於1就會列印並且丟擲異常。但是由於我們有裝飾器函數 retry,所以在發生異常就會重新再次執行方法,直到隨機整數大於1,就會列印“good job!”。

做人不能太固執

這種無休止地重試,簡直是浪費生命,浪費資源。我們要建設綠色家園,所以不妨加點限制:

# 最大重試次數
@retry(stop_max_attempt_number=5)
def do_something_limited():
    print("do something several times")
    raise Exception("raise exception")

do_something_limited()

珍惜有限的時間

一寸光陰一寸金,寸金難買寸光陰。我們要珍惜有限的時間,所以不妨給我們的重試加個時間限制:

# 限制最長重試時間(從執行方法開始計算)
@retry(stop_max_delay=5000)
def do_something_in_time():
    print("do something in time")
    raise Exception("raise exception")

do_something_in_time()

駐足欣賞路上風景

人生匆匆數十載,不要一路狂奔而忘記欣賞路邊的美景,有時候我們需要花點時間來欣賞一路的美景:

# 設定固定重試時間
@retry(wait_fixed=2000)
def wait_fixed_time():
    print("wait")
    raise Exception("raise exception")

wait_fixed_time()

給失敗設個限

雖說我們需要屢敗屢戰的韌性,但是失敗也要有個限度,不能在失敗中度過一生:

# 設定重試時間的隨機範圍
@retry(wait_random_min=1000,wait_random_max=2000)
def wait_random_time():
    print("wait")
    raise Exception("raise exception")

wait_random_time()

有些人值得等待

茫茫人海中,我就是要等到那個對的人:

# 根據異常重試
def retry_if_io_error(exception):
    return isinstance(exception, IOError)

# 設定特定異常型別重試
@retry(retry_on_exception=retry_if_io_error)
def retry_special_error():
    print("retry io error")
    raise IOError("raise exception")

retry_special_error()

我們自己定義一個函數,判斷異常型別,然後將函數作為引數傳給裝飾函數 retry ,如果異常型別符合,就會進行重試。

有些結果是我們希望見到的

人生並不是一帆風順,有些時候我們會遇到挫折,這些挫折也許在一開始就是我們想要的:

# 通過返回值判斷是否重試
def retry_if_result_none(result):
    """Return True if we should retry (in this case when result is None), False otherwise"""
    # return result is None
    if result =="111":
        return True


@retry(retry_on_result=retry_if_result_none)
def might_return_none():
    print("Retry forever ignoring Exceptions with no wait if return value is None")
    return "111"

might_return_none()

這裡我們定義了一個判斷返回值的函數,然後將這個函數作為引數傳給 retry 裝飾函數。當結果返回是“111”時,就會一直重試執行 might_return_none 函數。

生活豐富多彩,並不單調

我們的生活是豐富多彩的,從來都沒有很單調。所以上面這些引數,我們可以隨意組合使用,並不限定每次只能用一個。比如你可以限定遇到 IOError 時進行重試,並且重試次數最多5次。

總結

人生不可重來,但是Python可以重試!

我已經將retrying 這個裝飾函數的使用方法毫無保留地奉獻給各位看官了,趕快用起來吧!

到此這篇關於Python例外處理如何寫得優雅的文章就介紹到這了,更多相關Python例外處理內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com