程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python零基礎入門-8 錯誤和異常

編輯:Python

8.錯誤和異常

8.1 常見報錯

程序中經常會出錯,常見的錯誤包括但不限於:

  • 語法錯誤:“SyntaxError:invalid syntax”

  • 異常:xxError,如NameError、TypeError、IndentationError、ModuleNotFoundError等

語法錯誤,在運行前就可以發現。如果使用PyCharm會有紅色波浪線提醒你,請檢查拼寫縮進符號等是否符合語法。(SyntaxError也是一種異常,但是因為它比較特殊,在運行前就可以檢查出來,所以單獨說。)

異常情況很多,需要根據報錯內容具體分析。下面我們看看異常到底是什麼以及如何處理異常。

8.2 異常

程序執行時往往會出現預期之外的錯誤,也就是異常

這些錯誤未必是程序設計的問題,也可能是用戶非法輸入、網絡問題等導致程序出錯。

例如一個計算器程序,用戶輸入1/0的時候,0作分母是無意義的。因此程序無法正常執行,引發報錯。

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

實際程序中,我們可能遇到各種異常。

內置異常 — Python 3.10.4 文檔裡提供了大多數可能的異常,如IO異常,迭代異常、編碼錯誤異常等等。

BaseException是所有異常的基類,它可以用來捕獲所有異常。

但更常用是ExceptionException是所有內置的非系統退出類異常的基類。 所有用戶自定義異常也應當派生自此類。

8.3 處理異常

8.3.1 try-except

一般用try-except 語句來提前預防錯誤。

語法格式:

try:
...
執行一些可能出錯的操作
except 異常類型:
...
對出錯進行一個說明和處理

例如,我們寫了一個從用戶輸入讀取a,b,並計算a/b的程序。

用戶可能輸入一個非數字內容,引發ValueError,也可能輸入0作為除數,引發ZeroDivisionError

於是我們把可能出錯的語句放在try裡面,並且用 except捕捉錯誤。

try:
a = int(input('a= '))
b = int(input('b= '))
print('a/b= ',a/b)
except (ValueError,ZeroDivisionError):
print("無效輸入,請重試")

try 語句的工作原理如下:

  • 首先,執行 try 子句 。

  • 如果沒有觸發異常,則跳過 except 子句try 語句執行完畢。

  • 如果在執行 try 子句時發生了異常,則跳過該子句中剩下的部分。 如果異常的類型與 except 關鍵字後指定的異常相匹配,則會執行 except 子句,然後跳到 try/except 代碼塊之後繼續執行。如果發生的異常與 except 子句 中指定的異常不匹配,則它會被傳遞到外部的 try 語句中;如果沒有找到處理程序,則它是一個 未處理異常 且執行將終止並輸出報錯信息。

except 子句 可以用帶圓括號的元組來指定多個異常,例如:

except (RuntimeError, TypeError, NameError):
pass

try後面可以接多個except,來捕獲多種異常。如果異常被前面的except捕獲了,則後面的except不會繼續執行:

import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print(err.args)
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except BaseException as err:
print(f"Unexpected {err=}, {type(err)=}")
raise

except 子句 可以在異常名稱後面用as指定一個變量。 這個變量會綁定到一個異常實例並將參數存儲在 instance.args 中。 print(err)會調用異常類的__str__() 方法,獲取表示異常的字符串。

8.3.2 try-except-else

try … except 語句具有可選的 else 子句,該子句如果存在,它必須放在所有 except 子句 之後。 else會在 try 子句 沒有引發異常時執行。 例如:

for arg in sys.argv[1:]:
try:
f = open(arg, 'r')
except OSError:
print('cannot open', arg)
else: #如果沒有異常,則讀取文件
print(arg, 'has', len(f.readlines()), 'lines')
f.close()

8.3.3 try-…-finally

try 語句還有一個可選子句finally,用於定義在所有情況下都必須要執行的清理操作。例如:

try:
raise KeyboardInterrupt
finally:
print('Goodbye, world!')

不論 try 語句是否觸發異常,都會執行 finally 子句。在實際應用程序中,finally 子句對於釋放外部資源(例如文件或者網絡連接)非常有用。

with 語句是try-finally的一種簡化寫法,相當於在後面隱藏了一個finally來清理資源:

with open("myfile.txt") as f:
for line in f:
print(line, end="")

try-finally 特殊情形:

以下內容介紹了幾種比較復雜的觸發異常情景:

  • 如果執行 try 子句期間觸發了某個異常,則某個 except 子句應處理該異常。如果該異常沒有 except 子句處理,在 finally 子句執行後會被重新觸發。

  • except 或 else 子句執行期間也會觸發異常。 同樣,該異常會在 finally 子句執行之後被重新觸發。

  • 如果 finally 子句中包含 breakcontinue 或 return 等語句,異常將不會被重新引發。

  • 如果執行 try 語句時遇到 break,、continue 或 return 語句,則 finally 子句在執行 breakcontinue 或 return 語句之前執行。

  • 如果 finally 子句中包含 return 語句,則返回值來自 finally 子句的某個 return 語句的返回值,而不是來自 try 子句的 return 語句的返回值。

8.4 拋出異常

8.4.1 raise 異常

raise語句可以拋出指定的異常:

raise 異常

raise NameError('HiThere')

在捕獲異常後如果不想處理,可以用單個raise重新拋出異常:

try:
raise NameError('HiThere')
except NameError:
print('An exception flew by!')
raise

8.4.2 異常鏈 raise from

raise 支持可選的 from子句,用於啟用鏈式異常。

如:raise RuntimeError from exc

轉換異常時,這種方式很有用。例如:

def func():
raise ConnectionError
try:
func()
except ConnectionError as exc:
raise RuntimeError('Failed to open database') from exc

異常鏈會在 except 或 finally 子句內部引發異常時自動生成。 這可以通過使用 from None 這樣的寫法來禁用:

try:
open('database.sqlite')
except OSError:
raise RuntimeError from None

8.3 用戶自定義異常

用戶可以通過自定義繼承Exception的類來實現自己的異常。大多數異常命名都以 “Error” 結尾,類似標准異常的命名。(第9章類將介紹如何定義類)

class MyError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
try:
raise MyError(42)
except MyError as e:
print(e)

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved