iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
Python

初學者的 30 天 Python 復健課程系列 第 19

復健第十九天:啊有錯誤又怎樣,try try 看就知道

  • 分享至 

  • xImage
  •  

本來今天想用「讓我們捕捉每一個錯誤,成為 Python 大師」做為今天的文章標題,結果想起來前幾篇已經用過「大師」一詞——復健第十五天:成為串列大師吧——串列推導式 List Comprehension,只好放棄了。

怎麼樣捕捉 Python 裡的錯誤?

今天的主題算是延續復健第十七天:寫程式就是一場錯誤 Type Errors 的冒險,在認識 Python 各種錯誤類型後,我們可以試著預測可能發生的錯誤,並針對這些錯誤做排除與提示,這時候我們要學習使用兩顆神奇寶貝球——tryexcept

如何使用 try 和 except

這邊用「捕捉(catch)」可能會讓初學者有些困惑,如果要淺顯易懂地解釋,應該說是「如果程式碼可以正常運行,那就順利地執行下去」,但「如果發生錯誤的話,請 Python 不要默不作聲,並且告訴我們指定的錯誤訊息,或是按照我們的指示進行處理」,不過通常還是會用「捕捉(catch)」這個動詞。

為了「捕捉」 Python 裡的錯誤,我們使用 tryexcept 來「優雅地」處理錯誤、優雅地退出。

為什麼要強調「優雅地」處理錯誤呢?因為這是一個常見的程式設計慣用語法,當程式偵測到嚴重錯誤時,可以以受控的方式「優雅退出」,而非莫名其妙地結束、壞掉。另外,通常程式會在退出時,印出錯誤的訊息到終端或日誌(log),這樣可以讓應用程式更加健全。

錯誤的原因往往來自程式外部,例如:不正確的輸入、錯誤的檔名、找不到檔案、設備故障等,透過「優雅地」處理錯誤可以防止我們的應用程式無預警地崩潰。

在 Python 中的 tryexcept 語法如下:

try:
    如果程式正常運行,執行這個區塊的程式碼
except:
    如果發生錯誤,執行這個區塊的程式碼

透過使用 except,當 try 區塊發生錯誤時,程式不會毫無頭緒地引發錯誤,讓我們透過範例來理解。

try:
    print(10 + '5')
except:
    print('發生了一些錯誤')

在上述範例中,try 區塊的程式碼,會因為無法將整數 integer 與字串 string 進行相加而引發錯誤。我們可以將字串 '5' 轉換為 floatint,來讓這段程式碼正常運行。不過,如果不做任何更改,將執行 except 區塊,並在終端顯示出發生了一些錯誤的訊息。

如何嘗試捕捉錯誤?

首先我們先看一下下面這段程式碼:

try:
    name = input('請輸入你的名字: ')
    year_born = input('請輸入你的出生年份: ')
    age = 2024 - year_born
    print(f'你叫 {name},你的年齡是 {age}。')
except:
    print('發生了一些錯誤')

如果執行上述程式,在使用者輸入值後,終端會顯示「發生了一些錯誤」。(如果不知道為甚麼會發生錯誤,代表不夠瞭解 input() 這個函數喔!)

雖然我們可以透過 except 區塊的程式碼被執行,得知有錯誤發生,但我們卻無法得知具體的問題是什麼,為了瞭解問題,我們可以使用不同的錯誤類型來進行錯誤的捕捉。

我們可以這樣改寫本來的程式碼:

try:
    name = input('請輸入你的名字: ')
    year_born = input('請輸入你的出生年份: ')
    age = 2019 - year_born
    print(f'你叫 {name},你的年齡是 {age}。')
except TypeError:
    print('發生了型別錯誤')
except ValueError:
    print('發生了值錯誤')
except ZeroDivisionError:
    print('發生了除以零錯誤')

當我們再次執行程式並輸入值,會顯示 TypeError,並印出'發生了型別錯誤',讓我們知道是甚麼樣的錯誤。

在捕捉錯誤之後,我們甚至可以進一步告知 Python 接下來該怎麼辦,所以我們可以再使用 elsefinally 讓整個程式碼更加完整:

try:
    name = input('請輸入你的名字: ')
    year_born = input('請輸入你的出生年份: ')
    age = 2019 - year_born
    print(f'你叫 {name},你的年齡是 {age}。')
except TypeError:
    print('發生了型別錯誤')
except ValueError:
    print('發生了值錯誤')
except ZeroDivisionError:
    print('發生了除以零錯誤')
else:
    print('我通常會與 try 區塊一起執行')
finally:
    print('我總是會執行')

由於程式中仍然發生了錯誤,因此 else 區塊不會被執行,如果要讓 else 區塊能被執行,我們需要先修正 try 區塊的程式碼,避免 TypeError 的錯誤發生,修改之後如下:

try:
    name = input('請輸入你的名字: ')
    year_born = input('請輸入你的出生年份: ')
    age = 2019 - int(year_born)  #修改了這裡
    print(f'你叫 {name},你的年齡是 {age}。')
except TypeError:
    print('發生了型別錯誤')
except ValueError:
    print('發生了值錯誤')
except ZeroDivisionError:
    print('發生了除以零錯誤')
else:
    print('我通常會與 try 區塊一起執行')
finally:
    print('我總是會執行')

萬一我不知道可能發生的錯誤類型有哪些怎麼辦?

如果各位看倌有看過周星馳的《九品芝麻官》就知道,小朋友才做選擇,大人都是「我全都要」,所以當我們不確定程式執行時可能會引發哪種錯誤時,我們可以選擇「捕捉所有類型的錯誤」,在 Python 中可以使用 Exception 來捕捉所有類型的錯誤。

try:
    name = input('請輸入你的名字: ')
    year_born = input('請輸入你的出生年份: ')
    age = 2019 - int(year_born)
    print(f'你叫 {name},你的年齡是 {age}。')
except Exception as e:
    print(e)

現在,如果在 year_born 輸入的過程中輸入了字串而非數字,終端將會印出 Exception 的錯誤訊息,並高知發生了什麼錯誤。

後記

此時此刻的我,因為工作關係而在澳門,差一點點就忘記要寫鐵人賽文章,人出國了,什麼都忘記了,寫一個鐵人賽,可以認識自己很多的弱點,希望明後兩天不會忘記!


上一篇
復健第十八天:操控時間是一種超能力——datetime 模組
下一篇
復健第二十天:不用不知道,用過才知道的 RegEx 正規表達式
系列文
初學者的 30 天 Python 復健課程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言