0基礎學Python之二十四:異常處理(上)

0基礎學Python之二十四:異常處理(上)

來自專欄可樂編程0基礎學Python之二十四:異常處理(上)?

v.qq.com

Hi 大家好,我是王可樂,歡迎回到我們的零基礎學 Python 課程。學完了可樂前面的課程,相信大家已經對 Python 有了一個基本的認識和掌握。可樂也一直在鼓勵大家跟著我們的課程進行實際操作練習,以熟悉和鞏固學到的知識。

如果你的代碼和數據沒有問題,那麼 Python 就可以幫你運行代碼邏輯,得到結果。然而在實際練習和編碼中,我們經常會遇到發生錯誤和異常的情況。例如在前面的課程中,我們遇到過語法錯誤、名字錯誤、類型錯誤、文件不存在錯誤等等。

很多時候,寫代碼出現錯誤是難免的。今天的課程里,可樂就開始為大家講解一下 Python 中的錯誤;並且教大家發現錯誤、識別和定位錯誤原因,以及用防禦性代碼來處理錯誤。

我們先來看一下語法錯誤。我們說 Python 代碼必須按照規定的語法來書寫,否則就無法運行。例如,我們打開 Python Shell 輸入:

>>> print("Hello World File "<stdin>", line 1 print("Hello World ^SyntaxError: EOL while scanning string literal

出現了錯誤提示。我們看最後一行,可以看到,Python 告訴我們這裡發生了一個語法錯誤,也就是 SyntaxError。然後,Python 用一個向上的小箭頭指向了我們語句中出錯的地方,告訴我們是在 world 一詞的後面出現的錯誤;並且,SyntaxError 冒號後面的錯誤提示說:在掃描字元串時遇到了 EOL。

這裡,EOL 是 End Of Line 的縮寫。因此這個提示的意思就是,Python 正在掃描處理字元串時,錯誤遇到了一個行尾。可樂前面講過,正常的語法里,雙引號包裹的字元串是不能跨行的,除非行尾換行符用轉義字元反斜線轉義。因此,通過認真閱讀 Python 的錯誤提示,我們就可以快速找到出錯的地方。

此外,這個錯誤提示第一行 File stdin, line 1 ,其實是向我們說明了出錯代碼的文件名和行號。這裡,由於可樂在是 Python Shell 里演示的出錯語句,因此文件名顯示是 stdin,它叫做標準輸入。這就是說,出錯的是可樂剛剛從鍵盤輸入到 Shell 上的代碼;由於 Shell 總是從一個新的三大於號符號開始計算行號,因此這裡顯示行號為一。如果我們寫一個 Python 腳本,裡面發生了語法錯誤,那麼 Python 就會顯示這個腳本文件的名字,以及出錯代碼的真正行號了。大家可以自己試一試哦。

語法錯誤一般比較容易發現,也比較容易解決。更多的時候,儘管代碼的語法沒有問題,但是運行起來也會發生錯誤。我們把這種語法正確,但運行時發生的錯誤稱作異常,就是英文的 Exception。實際上,異常是我們寫代碼時遇到的主要錯誤類型。

我們先來看幾個異常的例子,這幾個例子都來自 Python 的官方文檔。

>>> 10 * (1/0) # 出現一個除 0 的異常Traceback (most recent call last): File "<stdin>", line 1, in <module>ZeroDivisionError: division by zero>>> 4 + spam*3 # 出現一個變數未定義的名字異常Traceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name spam is not defined>>> 2 + 2 # 由於不能把字元串和數字相加,出現一個類型異常Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: must be str, not int

我們看到,這三行代碼出現了三種不同的異常,分別是 ZeroDivisionError, NameError, 和 TypeError,這三個名字叫做異常的類型。Python 把程序運行中可能出現的異常按照類型來歸類,方便後續對異常的統一處理。實際上,每一個異常的類型都是一個叫做"類"的東西,由於我們的初級課程還沒有涉及面向對象編程的有關知識,可樂就不展開講解了。

異常類型之後,冒號後面,列印的是一行提示性的文字,它們一般提示了異常出現的原因。例如,第一個異常是我們把 0 當作了除數;第二個異常是 spam 這個名字沒有定義;最後一個異常則是由於加號前面是字元串,因此後面也必須使用字元串類型而不是整數類型。

和前面的語法錯誤類似,Python 也指出了錯誤發生時的文件和行號等信息,此外,還有一個錯誤發生的上下文信息,這裡是 <module>,以及錯誤的 Traceback 信息。什麼是 Traceback 和上下文信息呢?我們來看一個例子。首先,我們在 C:colecode 目錄下新建一個 Python 文件,命名為 test_err.py:

def devide(a, b): # 首先,我們定義一個函數,兩個數相除 return a / bprint(devide(1, 0)) # 然後,我們調用上面的函數,計算兩個數相除

保存文件內容,然後我們打開 cmd 終端,cd 切換到 C:colecode,然後輸入 python 空格 test_err.py,回車。

$ python test_err.pyTraceback (most recent call last): File "test_err.py", line 4, in <module> print(devide(1, 0)) File "test_err.py", line 2, in devide return a / bZeroDivisionError: division by zero

可以看到,代碼報了一個除 0 的錯誤。並且提示了兩個出錯的地方,分別是文件的第二行和第四行。什麼意思呢?實際上這裡的兩個出錯的地方展示了代碼的調用關係,而 Traceback 就是沿調用關係回溯的意思。這個出錯信息應該自上而下這麼來閱讀:

  1. 首先,出錯的地方在第四行,我們看到,這行代碼調用了 devide() 函數;
  2. 然後,在 devide 函數的內部,實際上是代碼第二行該函數的 return 語句之處報了錯;
  3. 那麼報了什麼錯呢,除零錯誤;

這樣,我們就找到了錯誤的原因。當然,我們這裡的例子只有兩個層級,錯誤也比較簡單,如果遇到比較複雜的調用關係,就需要大家仔細追溯代碼邏輯,慢慢來尋找問題所在了。這時,這裡的 Traceback 信息就是一個非常有用的線索了。

此外,我們還看到,上述錯誤提示信息的行號後面還有一個 in 某某地方的提示。這個提示叫做上下文提示,例如上面例子的第二行,就提示這裡位於函數 devide 內部;而第四行的 in 後面是 module,這個符號其實就是表示錯誤發生在代碼的最外層。

除了我們前面見到過的這幾個異常類型,Python 中還有相當多其他內置的異常類型。並且,Python 還支持自定義的異常類型,因此各種第三方模塊、框架等也可能有自己獨特的異常類型。

如果你以後編寫自己的代碼,不可避免的會遇到各種各樣的異常。一般來說,遵循可樂上面提到的方法,都能夠找到異常發生的原因,從而想辦法解決它。如果你遇到了從來沒有遇到過的異常,也不用擔心,網路上有相當多的資源可以查詢。例如 Python 的官方文檔、牛客網社區、Stack Overflow 社區等國內外資源。在搜索引擎中搜索你遇到的異常信息,很多時候都能找到異常發生的原因和解決方案。

除了通過修改代碼來解決異常,Python 還支持一種稱作異常捕獲的處理方式。不過,由於時間的關係,可樂今天就先講到這裡。

下一節課里,可樂會為大家介紹 Python 的異常捕獲語法,並且為我們第二課的小遊戲加入異常處理的功能,使它運行更加穩定。敬請期待哦。如果你喜歡我們的課程,歡迎關注我們的公眾號「可樂編程」,同時也請轉發給你的朋友們哦。可樂感謝大家的支持,我們下次課再見!


推薦閱讀:

TAG:Python入門 | 編程入門 | Python |