1. 程式人生 > >零基礎學習 Python 之錯誤 & 異常

零基礎學習 Python 之錯誤 & 異常

寫在之前

從今天開始一個新的篇章又要開始了,這次要寫的「錯誤 & 異常」知識點比較少,不像「類」那樣知識點那麼多,所以稍微好過一點。

對於程式在執行過程中因為錯誤或者其它原因而中止的現象,我們在之前文章的程式碼中已經看過很多次了,那些都可以歸為「錯誤 & 異常」現象,我們接下來就是要對這種現象進行近距離的觀察和處理。

錯誤

其實不管是弱雞還是大佬,在寫程式碼的時候錯誤往往是難以避免的,可能是因為手殘,也可能是因為拼寫錯誤,當然還有可能是某些比較玄學的錯誤,比如逗號寫成全形的等等等等。總之,寫程式碼中有相當一部分工作就是要不停的修改錯誤。

Python 中的錯誤之一就是「語法錯誤」(Syntax Errors),比如:

>>> for i in range(5)
 File "<stdin>", line 1
   for i in range(5)
                   ^
SyntaxError: invalid syntax

上面的那行程式碼裡因為缺少冒號,導致直譯器無法解釋,於是報錯,這個報錯其實是 Python 的語法分析器完成的,並檢測到了錯誤所在的檔案和行號( File “”, line 1 ),還以向上的箭頭 ^ 標識錯誤的位置,最後顯示錯誤型別。

另一種錯誤就是我們常說的「邏輯錯誤」,邏輯錯誤可能是由不合法或者不完整的輸入導致的,也可能是無法計算等,或者是其它的邏輯問題。邏輯錯誤不是由 Python 來檢查的,所以此處我們所談的錯誤不包括邏輯錯誤。

異常

當 Python 檢測到一個錯誤時,直譯器就無法繼續執行下去,於是就丟擲提示資訊,即為「異常」。有錯誤時,程式執行過程就會出現異常,讓我們先來看一個小例子:

>>> 10 / 0
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

當 Python 丟擲異常的時候,首先有「跟蹤記錄」或者叫「回溯」,後面顯示異常的詳細資訊,包括異常所在的位置,最後一行是異常型別及導致異常的原因。在上面的例子中,明確的告訴我們異常的型別是 ZeroDivisionError,並且對此異常型別做了解釋。

異常的型別有很多,我在這說幾個常見的型別:

NameError
嘗試訪問一個沒有申明的變數

ZeroDivisionError
除數為零

SyntaxError
語法錯誤

IndexError
索引超出序列範圍

KeyError
請求一個不存在的字典關鍵字

IOError
輸入/輸出錯誤

AttributeError
嘗試訪問未知的物件屬性

為了能夠更好的深入理解,我在這舉幾個例子,展示一下其中幾個異常出現的條件和結果:

1.NameError

>>> rocky
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
NameError: name 'rocky' is not defined

在 Python 中雖然不需要在使用變數之前宣告型別,但也需要對變數進行賦值,然後才可以使用,不被賦值的變數不能在 Python 中存在,因為變數相當於一個便籤,要把它貼到物件上才有意義。

2.IndexError & KeyError

>>> a = [1,2,3]
>>> a[4]
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
IndexError: list index out of range

>>> b = {'name':'rocky'}
>>> b['age']
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'age'

這兩個用我們俗語來說就是「雞蛋裡挑骨頭」,一定得報錯了,不過在實際程式設計的時候,特別是迴圈的時候,常常由於迴圈條件設定的不合理從而出現這種型別的錯誤。

3.IOError

>>> f = open('test')
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'test'

如果你確認有檔案,就一定要把路徑寫正確,因為你並沒有告訴 Python 要對你的計算機進行全身搜查,所以 Python 會按照你指定的未知去找,找不到就會出現異常。

這裡只是幹說其實沒有什麼效果,具體的還是要在實際程式設計中碰到才會印象深刻,這裡你先把常見的幾個記住,到時候別出現問題的時候不知道是什麼錯誤。

當你在執行程式的時候遇到異常時,不要慌張,這個其實是好事情,是 Python 在幫助你修改錯誤。只要你認真的閱讀異常資訊,再用我們之前學過的 dir(),help() 或官方文件,搜尋工具等來協助,就一定會解決問題。

處理異常

程式出現了異常就要「處理異常」。

首先,讓我們先來看一段程式碼:

while True:
   print('this is a division program.')
   a = input("input 'a' continue,otherwise logout:")
   if a == 'a':
       x = input('first number')
       y = input('second number')
       try:
           print(float(x)/float(y))
           print('***************')
       except ZeroDivisionError:
           print('the second number can not be zero.')
           print('***********************************')

   else:
       break

執行上面的程式碼,顯示的結果如下:

this is a division program.
input 'a' continue,otherwise logout:a
first number5
second number2
2.5
***************
this is a division program.
input 'a' continue,otherwise logout:a
first number5
second number0
the second number can not be zero.
***********************************
this is a division program.
input 'a' continue,otherwise logout:b

從執行的情況來看,當在第 2 個數,即除數為 0 時,程式並沒有因為這個錯誤而停止,而是給了一個很友好的提示,讓我們有機會改正錯誤,這完全得益於「異常處理」的設定,如果沒有處理異常的機制,當異常出現的時候程式就會中止。

1.try…except…

對於上面的例子,只看到了 try 和 except 部分,如果沒有異常發生的話,except 在 try 執行後被忽略;如果 try 子句中有異常的話,則該部分的其它子句被忽略,直接跳到 except 部分,執行其後面指定的異常型別及其子句。

except 後面也可以沒有任何異常型別,即無異常引數。如何這樣的話,不論 try 部分發生什麼異常,都會執行 except。

2.處理多個異常

try…except… 是處理異常的基本方式,在此基礎上,還可以擴充套件,也就是能夠處理多個異常。

這裡所說的處理多個異常,並不是因為同時報出多個異常,而是程式在執行中,只要遇到一個異常就會反應,所以每次捕捉到的異常一定是一個,由不同的 except 子句處理。

3. else 子句

其實有了 try…except…,在一般情況下是夠用的,但怕就怕在總有不一般的情況出現,所以就增加一個 else 子句,這個其實就和我們說的話一樣,總要根據需要新增不少東西。

try:
   print('just try')
except:
   print('just except')
else:
   print('i am else')

上述程式碼的執行結果如下:

just try
i am else

上述程式碼能夠幫助我們理解 else 的執行特點:如果 try 被執行了,則 except 被忽略,但是 else 被執行。然後我們在來看下面的程式碼:

try:
   print(1/0)
except:
   print('just except')
else:
   print('i am else')

上述程式碼的執行結果如下:

just except

這個時候,else 就不被執行了,兩個例子幫助我們瞭解了 else 的執行特點。

4.finally

finally 子句,一看這個名字,就感覺這是做善後工作的。的確如此,如果有了 finally ,不管前面執行的是 try 還是 except,最終都要執行它。因此,有一種說法是將 finally 用在可能的異常後進行清理,請看下面的例子:

x = 10

try:
   x = 1 / 0
except Exception as e:
   print(e)
finally:
   print(e)
   del x

上述程式碼的執行結果如下:

integer division or modulo by zero
del x

我們來看一看 x 是否被刪除:

>>> x
Traceback (most recent call last):
 File "test_search.py", line 1, in <module>
   print(x)
NameError: name 'x' is not defined

當然,在應用裡面可以將上面的各個句子綜合起來使用,寫成下面這樣:

try:
   do something

except:
   do something

else:
   do something
   
finally:
   do something

寫在最後

更多內容,歡迎關注公眾號「Python空間」,期待和你的交流。
在這裡插入圖片描述

也歡迎新增我個人微信,備註「CSDN」,一起交流學習。
在這裡插入圖片描述