Python異常處理,告別xxxxError

2021-02-14 簡說Python


文章來源:王的機器

作者:王聖元

從上貼【錯誤類型】的內容我們知道,Python 在程序報錯時會返回詳細信息,如錯誤發生的行數和具體的錯誤類型。

首先需要明白的是,我們無法完全阻止錯誤發生,但是可以提前預防以至於程序不會崩潰。這個提前預防的動作稱為異常處理(exception handling)。

總之異常處理就是為了防患於未然。

本帖的內容如下:

try-except

try-except-else

try-except-else-finally

拋出 Exception

總結


異常處理最常見的語句就是 try-except 組合,細分又有三種類型:

知道錯誤但不確定類型,用 except Exception

知道錯誤而且確定類型,用 except some_exception

知道錯誤而且有多個錯誤



def divide(a, b):    try:        c = a / b        print(f"Result = {c:.4f}.")    except:        print('Divisor is zero and division is impossible!')

Divisor is zero and division is impossible!


在做除法時我們知道分母為零會報錯,因此我們把 c = a/b 這行代碼寫在 try 語句下面。測試代碼:




其實上面錯誤的具體類型我們是可以查出來的,輸入 10/0,得到該錯誤是 ZeroDivisionError。


ZeroDivisionError Traceback (most recent call last)
<ipython-input-4-e574edb36883> in <module>
----> 1 10/0

ZeroDivisionError: division by zero


這樣我們在用 except 語句處理異常時,可以在後面「顯性」寫出我們要處理的錯誤類型,即 ZeroDivisionError。

def divide(a, b):    try:        c = a / b        print(f"Result = {c:.4f}.")    except ZeroDivisionError:        print('Divisor is zero and division is impossible!')

Divisor is zero and division is impossible!

運行結果沒問題。

但是在實際寫代碼中,你不知道會犯什麼稀奇古怪的錯誤,如下代碼第 4 行。變量 cc 在使用之前沒有定義,報錯。

def divide(a, b):    try:        c = a / b        d = cc + 1        print(f"Result = {c:.4f}.")    except ZeroDivisionError:        print('Divisor is zero and division is impossible!')


NameError Traceback (most recent call last)
<ipython-input-8-15fa568ba405> in <module>
----> 1 divide(10, 2)

<ipython-input-7-97d83e2f78ac> in divide(a, b)
      2     try:
      3         c = a / b
----> 4 d = cc + 1
      5         print(f"Result = {c:.4f}.")
      6     except ZeroDivisionError:

NameError: name 'cc' is not defined

為了保險起見,我們在已經確定代碼會出現 ZeroDivisionError 的情況下,將不確定的所有錯誤都放在 except Exception 後的語句中處理,即列印出 『Something wrong!』

def divide(a, b):    try:        c = a / b        d = cc + 1        print(f"Result = {c:.4f}.")    except ZeroDivisionError:        print('Divisor is zero and division is impossible!')    except Exception:        print('Something wrong!')

Divisor is zero and division is impossible!




假設你預期代碼會出現 ZeroDivisionError 和 NameError 的錯誤,你可以用多個 except 語句來實現。

def divide(a, b):    try:        c = a / b        d = cc + 1        print(f"Result = {c:.4f}.")    except ZeroDivisionError:        print('Divisor is zero and division is impossible!')    except NameError:        print('Some variable name is undefined!')

Some variable name is undefined!

Divisor is zero and division is impossible!


運行結果沒問題。

此外,你還可以將多個 except 語句整合到第一個 except 語句中,範式如上。

兩者幾乎是等價的,下面我們換個例子來分析兩者的區別。


下面函數將變量 a 轉換成整數

如果 a 是浮點型變量 1.3 或者字符型變量 '1031',程序運行正常。

如果 a 是這種字符型變量 '1 mio',會報 ValueError 的錯誤。

如果 a 是列表型變量 [1, 2],會報 TypeError 的錯誤(這對元組、字典、集合都適用)。

def convert_to_int(a):    try:        int_value = int(a)        print('The converted integer is', int_value)    except ValueError:        print("'a' is not a numerical value or expression.")    except TypeError:        print("The type of 'a' is not compatiable.")

當程序正常運行而轉換成整型變量的輸出。

The converted integer is 1

The converted integer is 1031

當程序報錯但異常 ValueError 被處理時的輸出。

'a' is not a numerical value or expression.


當程序報錯但異常 TypeError 被處理時的輸出。

The type of 'a' is not compatiable.



我們可以將多個 except 語句寫到一個 except 語句中,兩者等價關係如下:

    except exc_1:

    except exc_2:

    ...

    except exc_n:

=

    except (exc_1, exc_2, ... exc_n)

關鍵點就是要用小括號把每個特定異常「打包」起來。

def convert_to_int(a):    try:        int_value = int(a)        print('The converted integer is', int_value)    except (ValueError, TypeError):        print("Error occurred. Either 'a' is a numerical value " \              "or expression or type of 'a' is incompatible.")

結果運行如下。

Error occurred. Either 'a' is a numerical value or expression or type of 'a' is incompatible.

Error occurred. Either 'a' is a numerical value or expression or type of 'a' is incompatible.


哪種範式更好呢?

此外我們還可以給異常起別名(alias),用以下範式,別名可以任意取,一般用 e 或者 err 當做其名稱。

    except (exp_1, ... exp_n) as err

def convert_to_int(a):    try:        int_value = int(a)        print('The converted integer is', int_value)    except (ValueError, TypeError) as err:        print('GOT ERROR WITH MESSAGE: {0}'.format(err.args[0]))

GOT ERROR WITH MESSAGE: invalid literal for int() with base 10: '1 mio'

GOT ERROR WITH MESSAGE: int() argument must be a string, a bytes-like object or a number, not 'list'

上節講了當異常被處理時運行 except 語句中的代碼,如果沒有異常出現,我們可以加一個 else 語句,而運行其下的代碼。這時就是 try-except-else 組合。

首先要明確的是,else 語句是可有可無的。如果存在,則 else 語句應始終在 except 語句之後。 

def divide(a, b):    try:        c = a / b    except ZeroDivisionError:        print('Divisor is zero and division is impossible!')    else:        print(f"Result = {c:.4f}.")

Divisor is zero and division is impossible!

假如不管異常是否出現我們都需要運行某些代碼,我們可以加 finally 語句。這時就是 try-except-else-finally 組合。

無論是否發生異常,finally 語句始終在 try 語句運行之前執行。

在實際應用中,finally 語句在程序跑完後用於釋放資源、關閉文件或斷開資料庫連接等。

def divide(a, b):    try:        c = a / b    except ZeroDivisionError:        print('Divisor is zero and division is impossible!')    else:        print(f"Result = {c:.4f}.")    finally:        print('Error or no error, FINALLY DONE!')

當異常出現的時候,沒問題,異常被處理了,而且在 finally 語句下的信息也隨後打出。

Divisor is zero and division is impossible!
Error or no error, FINALLY DONE!


當程序正常運行的時候,沒問題,結果打出,而且在 finally 語句下的信息也隨後打出。

Result = 5.0000.
Error or no error, FINALLY DONE!


當沒有實現預測的異常出現的時候,程序報錯,但是在 finally 語句下的信息還是會隨後打出。

Error or no error, FINALLY DONE!


TypeError Traceback (most recent call last)
<ipython-input-51-ae7e5f3b4399> in <module>
----> 1 divide(10, '2')

<ipython-input-48-ef792bab0247> in divide(a, b)
      1 def divide(a, b):
      2     try:
----> 3 c = a / b
      4     except ZeroDivisionError:
      5         print('Divisor is zero and division is impossible!')

TypeError: unsupported operand type(s) for /: 'int' and 'str'


這時為了處理「未預測」的異常,我們加一句 except Exception 即可。

def divide(a, b):    try:        c = a / b    except ZeroDivisionError:        print('Divisor is zero and division is impossible!')    except Exception:        print('Something wrong!')    else:        print(f"Result = {c:.4f}.")    finally:        print('Error or no error, FINALLY DONE!')

Something wrong!
Error or no error, FINALLY DONE!


再看一個從電腦硬碟中讀取文件(假設路徑中有一個 Error.txt 的文件)的例子。

finish_task = False
try: inputFileName = input("輸入要讀取的文件名 (txt 格式): ") inputFileName = inputFileName + ".txt" inputFile = open(inputFileName, "r")except IOError: print("\n文件", inputFileName, "不能被打開")except Exception: print("\n有不明錯誤")else: print("\n正在打開文件", inputFileName, "\n") finish_task = True
for line in inputFile: print(line, end="")
print("\n\n完成讀取文件", inputFileName)finally: if finish_task: inputFile.close() print("\n關閉文件", inputFileName) else: print("\n未能完成讀取文件", inputFileName)

按 Enter 下面的空白框會跳出來。

如果輸入一個錯誤的文件名,比如 asf。

輸入要讀取的文件名 (txt 格式): asf

文件 asf.txt 不能被打開

未能完成讀取文件 asf.txt


如果輸入一個正確的文件名,比如 Error。


輸入要讀取的文件名 (txt 格式): Error

正在打開文件 Error.txt

Errors or mistakes in a program are often referred to as bugs. They are almost always the fault of the programmer. The process of finding and eliminating errors is called debugging. Errors can be classified into three major groups:

I. Syntax errors
II. Runtime errors
III. Logical errors

完成讀取文件 Error.txt

關閉文件 Error.txt


除了上面處理異常的操作之外,我們還可以用 raise 關鍵詞「拋出」異常:

拋出 Python 裡內置的異常

拋出我們自定義的異常

在下例中,如果輸入非整數,我們拋出一個 ValueError(注意這是 Python 裡面內置的異常對象),順帶「This is not a positive number」的信息。

try:    a = int(input("Enter a positive integer: "))    if a <= 0:        raise ValueError("That is not a positive number!")except ValueError as err:    print(err)

在下例中,我們記錄連續兩天的組合價值

代碼如下:

def portfolio_value(last_worth, current_worth):    if last_worth < 0 or current_worth < 0:        raise ValueError('Negative worth!')    value = current_worth - last_worth    if value < 0:        raise ValueError('Negative return!')

兩種情況的運行結果如下:

try:    portfolio_value(-10000, 10001)except ValueError as err:    print(err)

try:    portfolio_value(10000, 9999)except ValueError as err:    print(err)


但是在第二種組合增值為負的情況下,嚴格來說不算是 ValueError,頂多算個警告,這時我們可以自定義一個 NegativePortfolioValueWarning 的異常。

在 Python 裡,所有異常都是 Exception 的子類,因此在定義其類時需要

class Error(Exception):

class your_exception(Error):

具體代碼如下。

class Error(Exception):    pass
class NegativePortfolioValueWarning(Error): def __init__(self, expression, message): self.expression = expression self.message = message

細分 ValueError 和 NegativePortfolioValueWarning 。

def portfolio_value(last_worth, current_worth):    if last_worth < 0 or current_worth < 0:        raise ValueError('Negative worth!')    value = current_worth - last_worth    if value < 0:        raise NegativePortfolioValueWarning(        'NegativePortfolioValueWarning', \        'Negative return. Take a look!')

兩種情況的運行結果如下:

try:    portfolio_value(-10000, 10001)except ValueError as err:    print(err)except NegativePortfolioValueWarning as err:    print('[', err.args[0], '] -', err.args[1])


try:    portfolio_value(10000, 9999)except ValueError as err:    print(err)except NegativePortfolioValueWarning as err:    print('[', err.args[0], '] -', err.args[1]

[ NegativePortfolioValueWarning ] - Negative return. Take a look!


一圖勝千言!

信息量太小?那這張呢?

如果你覺得文章還不錯,請大家點讚分享下。你的肯定是我最大的鼓勵和支持。

老表Pro已經滿了

所以大家加老表Max吧

每日留言

說說你最近遇到的一個編程問題?

或者新學的一個小技巧?

(字數不少於15字)

相關焦點

  • python異常處理與上下文管理器
    異常處理異常與錯誤錯誤可以通過IDE或者解釋器給出提示的錯誤opentxt('a.jpg','r')語法層面沒有問題,但是自己代碼的邏輯有問題if age>18: print('未成年')異常多指在程序執行過程中,出現的未知錯誤,語法和邏輯本身是正確的。
  • [Python]文件與異常的錯誤處理
    [Python]文件與異常的錯誤處理1.># 輸出了4個字符E:\Github\python\env\Scripts\python.exe E:/Github/python/files_error/fileIO/fileIO.pyMan: 2.
  • python教程之九錯誤和異常處理
    大多數的異常都不會被程序處理,都以錯誤信息的形式展現在這裡:>>> 10 * (1/0)Traceback (most recent call last):File "<pyshell#78>", line 1, in <module>10 * (1/0)ZeroDivisionError
  • Python異常處理
    問題描述大家在使用python語言寫代碼的時候難免會出一些錯誤,而才入門的朋友們往往不知道是哪裡出了錯或者不知道自己錯在哪裡、什麼錯誤。所以我們要知道是哪行代碼出錯,其次室錯誤的類型是什麼,錯在那個細節,逐步分析,從而解決錯誤並改正。
  • python入門——Python中異常處理
    python大數據課堂已經開始了。想轉行大數據,數據挖掘,機器學習,人工智慧的小夥伴可以關注啦。上一篇帶大家了解了python中的I/O函數。今天我們來繼續了解python中的異常處理。調試環境以python3.6環境為例。需要代碼和demo的朋友可以搜索「欒鵬全棧」到我的CSDN博客。
  • Day15.異常的處理
    異常else異常finally自定義異常異常在我們剛接觸python的時候,肯定遇到過無數次的報錯。python中有兩種錯誤很容易辨認:語法錯誤和異常。語法錯誤python的語法錯誤又稱為解析錯,多數是語法格式上出現問題。
  • 異常處理的其他3個小技巧
  • 一文看懂Python異常處理(exception, try和raise語句)
    即便Python程序的語法是正確的,還是會有各種各樣意想不到的異常或錯誤。大多數的異常都不會被程序處理,而是以錯誤信息的形式展現出來,如下所示:>>> 10 * (1/0)Traceback (most recent call last): File "<stdin>", line 1, in ?
  • Python智闡7-Python異常處理
    程序在編寫或運行過程中,難免會出現各種各樣的異常。有些異常需要我們去找出來改掉,有些異常是由於用戶操作導致的,則需要我們去提示規範。本次主要介紹Python中對異常的處理。1、try......except......else用法說明:1.1 else語句可有可無,可以有多個except語句1.2 執行到try後面的執行語句時,如果有異常,則進行"異常類別"匹配,返回第一個匹配到的異常類別的拋出語句1.3 可以寫多個except,也可以一個except對應多個"異常類別".
  • python基礎---異常處理
    程序的異常處理今天霖小白心血來潮想來分享一下python基礎中的如何異常處理,使程序有更好的用戶體驗。前言python程序對用戶的輸入有一定的要求,所以當實際輸入不滿足程序要求時,可能在程序運行過程中會直接報錯無法進行下一步的運行。
  • 第16天:Python 錯誤和異常
    處理程序只處理相應的 try 子句中發生的異常,而不處理同一 try 語句內其他處理程序中的異常。一個 except 子句可以將多個異常命名為帶括號的元組。>try: diyException(2) #執行異常方法except 'error level' as err: #捕獲異常 print(err) #列印異常參數#輸出Traceback (most recent call last): File "/Users/cxhuan/Documents/python_workspace/stock/test.py", line 51
  • python入門學習異常處理類型
    前言異常是指在程序執行過程中發生的一個事件,影響了程序的正常執行,例如:0做了分母。異常是Python對象,表示一個錯誤。當Python腳本發生異常時我們需要捕獲處理它,否則程序會終止執行。在Java語言中我們知道異常的常用結構為try catch組成,有時也會用到finally,那麼在python中異常是如何來處理的呢?python中的異常處理1.python異常簡單語法python異常的簡單語法為try-except-else語法,注意這裡的關鍵字是except而不是Exception,這與java是有區別的。
  • 小叮噹爬蟲基礎(三):cookie、代理設置、error異常處理
    而對cookie的使用以及基本的反爬措施---代理設置,error異常處理等是十分重要的。當網站的維護人員發現你是爬蟲後,肯定要對你做相應的處理。很有可能直接封掉你的IP哦!這樣一來,我們便無法訪問了對數據的獲取也就自然中止了。所以在做爬蟲項目時,用代理去代替我們訪問是每個爬蟲工程師必備的基本技能。在urlib中設置代理IP的步驟都是固定的。
  • python面向對象之異常處理
    異常的概念 程序在運行時,如果 `Python 解釋器` 遇到 到一個錯誤,會停止程序的執行,並且提示一些錯誤信息,這就是 異常 程序停止執行並且提示錯誤信息 這個動作,我們通常稱之為:拋出(raise)異常> 程序開發時,很難將 所有的特殊情況 都處理的面面俱到,通過 異常捕獲 可以針對突發事件做集中的處理,從而保證程序的 穩定性和健壯性
  • python 異常處理
    對於python來說,就是工廠類被具體工廠繼承。這樣在簡單工廠模式裡集中在工廠方法上的壓力可以由工廠方法模式裡不同的工廠子類來分擔。抽象的工廠類提供了一個創建對象的方法,也叫作工廠方法。1) 抽象工廠角色(Factory): 這是工廠方法模式的核心,它與應用程式無關。是具體工廠角色必須實現的接口或者必須繼承的父類。
  • python中的異常捕獲
    無論是編程新手還是老手,都會遇到過程序報錯,終止執行的情況,對於python的報錯信息,可以分為以下兩大類語法錯誤,syntax error
  • Python輸入,輸出,存儲器和異常
    描述r+w+a+當前文件不存在時文件 拋出異常 創建文件 創建文件 打開後原文件內容 保留 清空 保留 初始位置 0 0 文件尾 寫入位置 標記位置 標記位置 寫入時默認跳至文件尾補充個例子吧:test = '''\This is a program about file I/O.Author: RunsenDate: 2020/3/31'''f = open
  • Python文件和異常處理
    /test.txt", "w") as f:  f.write("xxxx") # 寫入數據, 具體方法可以參考help文檔2、異常處理即便程序的語法是正確的,在運行它的時候,也有可能發生錯誤。運行期檢測到的錯誤被稱為異常。
  • Python中異常重試解決方案
    原文:https://www.biaodianfu.com/python-error-retry.html作者:標點符全文約 2600 字,讀完可能需要 4 分鐘。在做數據抓取的時候,經常遇到由於網絡問題導致的程序保存,先前只是記錄了錯誤內容,並對錯誤內容進行後期處理。
  • 一篇文章幫你搞定Python異常處理
    =1+'str'什麼是異常異常就是程序運行時發生錯誤的信號,在python中,錯誤觸發的異常如下Python中異常種類在python中不同的異常可以用不同的類型(python中統一了類與類型,類型即類)去標識,不同的類對象標識不同的異常,一個異常標識一種錯# 觸發IndexErrorl=['run1','aa']