App下載

Python Try和Except語句——如何在Python中處理異常

益達(dá)學(xué)妹 2021-09-26 17:12:14 瀏覽數(shù) (9533)
反饋

使用 Python 編碼時(shí),即使是在語法和邏輯上正確的程序中,您也經(jīng)常會(huì)出現(xiàn)運(yùn)行時(shí)錯(cuò)誤。這些錯(cuò)誤可能是由無效輸入或某些前后矛盾引起的。在 很多語言中都提供了異常處理機(jī)制,在Python 中,您可以使用try和except塊來更優(yōu)雅地將大多數(shù)這些錯(cuò)誤作為異常處理。在本教程中,您將學(xué)習(xí)的一般語法try和except。然后我們將繼續(xù)編寫簡單的示例,討論可能出錯(cuò)的地方,并使用try和except塊提供糾正措施。

Python try 和 except 塊的語法

讓我們從了解Python 中try和except語句的語法開始介紹。通用模板如下圖所示:

try:
	# There can be errors in this block
    
except <error type>:
	# Do this to handle exception;
	# executed if the try block throws an error
    
else:
	# Do this if try block executes successfully without errors
   
finally:
	# This block is always executed

讓我們看看不同塊的用途:

  • 該try代碼塊是你想嘗試執(zhí)行的語句塊。但是,由于異??赡軙?huì)出現(xiàn)運(yùn)行時(shí)錯(cuò)誤,所以此塊可能無法按預(yù)期工作。
  • 該except代碼塊是觸發(fā)try塊時(shí)需要執(zhí)行的語句。它包含一組語句,這些語句通常會(huì)為您提供有關(guān)try塊內(nèi)出錯(cuò)的一些處理方法。
  • 您應(yīng)該始終提及您打算在代碼塊內(nèi)作為異常捕獲的錯(cuò)誤類型,由上述代碼段中的占位符表示。例如:except<error type>
  • 您也可以不在except指定<error type>. 但是,這不是推薦的做法,因?yàn)槟鷽]有考慮可能發(fā)生的不同類型的錯(cuò)誤。
在嘗試執(zhí)行try塊內(nèi)的代碼時(shí),也有可能發(fā)生多個(gè)錯(cuò)誤。

例如,您可能正在使用超出范圍的索引訪問列表,使用錯(cuò)誤的字典鍵,并嘗試打開一個(gè)不存在的文件 - 所有這些都應(yīng)該放在try塊內(nèi)。

在這種情況下,你可能會(huì)碰到?IndexError?,?KeyError?和?FileNotFoundError?。并且您必須添加與except您預(yù)期的錯(cuò)誤數(shù)量一樣多的每種類型的錯(cuò)誤一個(gè)。

  • 僅當(dāng)try塊在沒有錯(cuò)誤的情況下執(zhí)行時(shí),才會(huì)觸發(fā)else塊。當(dāng)您希望在try塊成功后執(zhí)行后續(xù)操作時(shí),這可能非常有用。例如,如果您嘗試成功打開一個(gè)文件,則可能需要讀取其內(nèi)容。

  • 該finally塊總是被執(zhí)行,而不管其他塊中發(fā)生了什么。當(dāng)您想在執(zhí)行特定代碼塊后釋放資源時(shí),這很有用。
注意:else和finally塊是可選的。在大多數(shù)情況下,您可以只使用try塊來嘗試做某事,并將錯(cuò)誤捕獲為except塊內(nèi)的異常。

在接下來的幾分鐘內(nèi),您將使用迄今為止學(xué)到的知識(shí)來處理 Python 中的異常。讓我們開始吧。

如何處理Python中的ZeroDivision(除零異常)錯(cuò)誤

考慮下面所示的函數(shù)divide()。它接受兩個(gè)參數(shù) num和div ,并返回除法運(yùn)算的商num/div。

def divide(num,div):
  return num/div

? 使用不同的參數(shù)調(diào)用函數(shù)會(huì)按預(yù)期返回結(jié)果:

res = divide(100,8)
print(res)

# Output
12.5

res = divide(568,64)
print(res)

# Output
8.875

此代碼工作正常,直到您嘗試除以零:

divide(27,0)

您會(huì)看到程序崩潰并拋出ZeroDivisionError:

# Output
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-19-932ea024ce43> in <module>()
----> 1 divide(27,0)

<ipython-input-1-c98670fd7a12> in divide(num, div)
      1 def divide(num,div):
----> 2   return num/div

ZeroDivisionError: division by zero

您可以通過執(zhí)行以下操作將此除以零作為異常處理:

  • 在try塊中,調(diào)用divide()函數(shù)。從本質(zhì)上講,您正在試圖將num除以div。
  • 當(dāng)div為0的情況作為except塊內(nèi)的異常處理。
  • 在此示例中,您可以通過打印一條消息來通知用戶他們嘗試除以零,從而排除?ZeroDivisionError?異常。

這顯示在下面的代碼片段中:

try:
    res = divide(num,div)
    print(res)
except ZeroDivisionError:
    print("You tried to divide by zero :( ")

使用有效的輸入,代碼仍然可以正常工作。

divide(10,2)
# Output
5.0

當(dāng)您嘗試除零時(shí),您會(huì)收到發(fā)生異常的通知,并且程序會(huì)正常結(jié)束。

divide(10,0)
# Output
You tried to divide by zero :(

如何在 Python 中處理 TypeError(類型異常)

在本節(jié)中,您將看到如何在 Python 中使用try和except處理一個(gè) TypeError。

? 考慮以下函數(shù)add_10(),它接受一個(gè)數(shù)字作為參數(shù),將其加 10,然后返回加法的結(jié)果。

def add_10(num):
  return num + 10

您可以使用任意數(shù)字參數(shù)調(diào)用該函數(shù),它會(huì)正常工作,如下所示:

result = add_10(89)
print(result)

#Output
99

現(xiàn)在嘗試add_10()使用"five"而不是調(diào)用5。

add_10("five")

您會(huì)注意到您的程序崩潰并顯示以下錯(cuò)誤消息:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-15-9844e949c84e> in <module>()
----> 1 add_10("five")

<ipython-input-13-2e506d74d919> in add_10(num)
      1 def add_10(num):
----> 2   return num + 10

TypeError: can only concatenate str (not "int") to str

該錯(cuò)誤消息?TypeError: can only concatenate str (not "int") to str?說明您只能連接兩個(gè)字符串,而不能向字符串添加整數(shù)。

現(xiàn)在,您有以下內(nèi)容:

  • 給定一個(gè)數(shù)字my_num,嘗試使用my_num作為參數(shù)調(diào)用函數(shù)add_10()。如果參數(shù)是有效類型,則不存在異常
  • 否則,將觸發(fā)與TypeError對(duì)應(yīng)的except塊,通知用戶參數(shù)的類型無效。

這一點(diǎn)解釋如下:

my_num = "five"
try:
  result = add_10(my_num)
  print(result)
except TypeError:
  print("The argument `num` should be a number")

由于您現(xiàn)在已?將TypeError?作為異常處理,因此您只會(huì)被告知參數(shù)的類型無效。

The argument `num` should be a number

如何在 Python 中處理 IndexError(無效索引)

如果您之前使用過 Python 列表或任何可迭代的 Python數(shù)據(jù)類型,您可能會(huì)遇到?IndexError?.

這是因?yàn)橥ǔ:茈y跟蹤可迭代對(duì)象的所有更改。并且您可能正在嘗試訪問無效索引處的項(xiàng)。

? 在這個(gè)例子中,列表my_list有 4 個(gè)項(xiàng)。如果使用負(fù)索引,則有效索引為 0、1、2 和 3,以及 -1、-2、-3、-4。

由于2是有效的索引,您可以看到索引2中的項(xiàng)被打印出來,即C++:

my_list = ["Python","C","C++","JavaScript"]
print(my_list[2])

#Output
C++

如果您嘗試訪問位于有效索引范圍之外的索引處的項(xiàng),您將遇到?IndexError?:

print(my_list[4])
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-7-437bc6501dea> in <module>()
      1 my_list = ["Python","C","C++","JavaScript"]
----> 2 print(my_list[4])

IndexError: list index out of range

如果您熟悉該模式,您現(xiàn)在將使用try和except來處理索引錯(cuò)誤。

? 在下面的代碼片段中,您嘗試訪問由 指定的索引處的項(xiàng)目search_idx。

search_idx = 3
try:
  print(my_list[search_idx])
except IndexError:
  print("Sorry, the list index is out of range")

這里,search_idx( 3) 是一個(gè)有效的索引,并且打印出特定索引處的項(xiàng)目:

JavaScript

如果search_idx超出索引的有效范圍,則 except 塊將 捕獲IndexError為異常,并且不再有錯(cuò)誤消息。

search_idx = 4
try:
  print(my_list[search_idx])
except IndexError:
  print("Sorry, the list index is out of range")

而是顯示search_idx超出有效索引范圍的消息:

Sorry, the list index is out of range

如何在 Python 中處理 KeyError(鍵值對(duì)異常)

在使用 Python 詞典時(shí)可能遇到過KeyError。

? 考慮這個(gè)例子,你有一本字典my_dict。

my_dict ={"key1":"value1","key2":"value2","key3":"value3"}
search_key = "non-existent key"
print(my_dict[search_key])
  • 字典my_dict有 3 個(gè)鍵值對(duì),"key1:value1", "key2:value2", 和"key3:value3"
  • 現(xiàn)在,您嘗試訪問字典并訪問與 key 對(duì)應(yīng)的值"non-existent key"。

正如預(yù)期的那樣,你會(huì)得到一個(gè)KeyError:

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-2-2a61d404be04> in <module>()
      1 my_dict ={"key1":"value1","key2":"value2","key3":"value3"}
      2 search_key = "non-existent key"
----> 3 my_dict[search_key]

KeyError: 'non-existent key'

幾乎可以像處理IndexError一樣處理KeyError.

  • 您可以嘗試訪問與指定的鍵對(duì)應(yīng)的值search_key。
  • 如果search_key確實(shí)是一個(gè)有效的鍵,則打印出相應(yīng)的值。
  • 如果由于密鑰不存在而遇到異常,您可以使用該except塊讓用戶知道。

這在下面的代碼片段中進(jìn)行了解釋:

try:
  print(my_dict[search_key])
except KeyError:
  print("Sorry, that's not a valid key!")
Sorry, that's not a valid key!

? 如果您想提供其他操作,例如無效密鑰的名稱,您也可以這樣做:密鑰可能拼寫錯(cuò)誤,使其無效。在這種情況下,讓用戶知道使用的密鑰可能會(huì)幫助他們修復(fù)拼寫錯(cuò)誤。

您可以通過捕獲無效密鑰<error_msg>并在發(fā)生異常時(shí)打印的消息中使用它來實(shí)現(xiàn)此目的:

try:
  print(my_dict[search_key])
except KeyError as error_msg:
  print(f"Sorry,{error_msg} is not a valid key!")

? 注意鍵名也是如何打印出來的:

Sorry,'non-existent key' is not a valid key!

如何在 Python 中處理 FileNotFoundError(文件找不到異常)

在 Python 中處理文件時(shí)發(fā)生的另一個(gè)常見錯(cuò)誤是FileNotFoundError.

? 在以下示例中,您嘗試通過指定open()函數(shù)的路徑來打開文件my_file.txt。并且您想讀取該文件并打印出該文件的內(nèi)容。

但是,您尚未在指定位置創(chuàng)建文件。

如果您嘗試運(yùn)行下面的代碼片段,您將得到FileNotFoundError:

my_file = open("/content/sample_data/my_file.txt")
contents = my_file.read()
print(contents)
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
<ipython-input-4-4873cac1b11a> in <module>()
----> 1 my_file = open("my_file.txt")

FileNotFoundError: [Errno 2] No such file or directory: 'my_file.txt'

并使用try和 except,您可以執(zhí)行以下操作:

  • 嘗試在try塊中打開文件。
  • 處理FileNotFoundError:通過except讓用戶知道他們?cè)噲D打開一個(gè)不存在的文件塊。
  • 如果try塊成功,并且文件確實(shí)存在,則讀取并打印出文件的內(nèi)容。
  • 在finally塊中,關(guān)閉文件,以免浪費(fèi)資源?;叵胍幌挛募⑷绾侮P(guān)閉,而不管文件打開和讀取步驟中發(fā)生了什么。
try:
  my_file = open("/content/sample_data/my_file.txt")
except FileNotFoundError:
  print(f"Sorry, the file does not exist")
else:
  contents = my_file.read()
  print(contents)
finally:
  my_file.close()

請(qǐng)注意您是如何將錯(cuò)誤作為異常處理的,程序結(jié)束時(shí)會(huì)優(yōu)雅地顯示以下消息:

Sorry, the file does not exist

? 讓我們考慮else觸發(fā)塊的情況。該文件my_file.txt現(xiàn)在位于前面提到的路徑中。

這是文件my_file.txt包含的內(nèi)容:

現(xiàn)在,重新運(yùn)行之前的代碼片段按預(yù)期工作。

這一次,文件my_file.txt存在,else塊被觸發(fā)并打印出其內(nèi)容,如下所示:

我希望這能闡明您在處理文件時(shí)如何處理異常。


0 人點(diǎn)贊