>> a = 2 >>> if a > 0 print( OK ); File , line 1 if..."/>
您好,登錄后才能下訂單哦!
在寫python代碼的過程中可能會(huì)出現(xiàn)一些錯(cuò)誤,這些錯(cuò)誤可區(qū)分為2類:語法錯(cuò)誤 和 異常~
>>> a = 2
>>> if a > 0 print('OK');
File "<stdin>", line 1
if a > 0 print('OK');
^
SyntaxError: invalid syntax
?
如上語句即 存在語法錯(cuò)誤,if 語句的條件后面沒有冒號(hào) ‘:’。
語法錯(cuò)誤也稱為解析錯(cuò)誤,這類錯(cuò)誤在程序執(zhí)行之前就會(huì)被Python解釋器檢測到。如果使用IDE工具開發(fā)(例如 pycharm),pycharm會(huì)直接使用下標(biāo)的紅線提示開發(fā)者這里存在語法錯(cuò)誤。這類錯(cuò)誤必須在程序運(yùn)行前就改正~
代碼不存在語法錯(cuò)誤,在運(yùn)行過程中出現(xiàn)的邏輯錯(cuò)誤,即為異常~
>>> 1 / 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>>
>>>
>>> lst = ['a', 'b', 'c']
>>> lst[2]
'c'
>>> lst[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
?
程序在運(yùn)行過程中,一旦發(fā)生異常,且發(fā)生的異常沒有被捕獲或者處理,則程序就會(huì)停止運(yùn)行。
?
異常有不同的類型,在發(fā)生異常時(shí),異常的類型及發(fā)生異常的原因 會(huì)被打印出來。上述示例中,第一個(gè)異常為 ZeroDivisionError(除數(shù)不能為0),第二個(gè)異常為 IndexError(列表指針超出范圍)。
?
ZeroDivisionError 和 IndexError 都為Python的內(nèi)置異常,即 python解釋器 已經(jīng)定義好的異常類型,常見的內(nèi)置異常還有:StopIteration,GeneratorExit,AssertionError,EOFError,IOError,OSError等等。關(guān)于Python的內(nèi)置異常及說明可參閱:https://docs.python.org/zh-cn/3.7/library/exceptions.html#bltin-exceptions
?
這些內(nèi)置異常都繼承于Exception類(自定義的異常一般也是直接或間接地繼承自Exception類),且所有 內(nèi)置異常的名稱都存在于 內(nèi)置名稱空間中,可直接使用,而不需要 'import exceptions模塊'。
try...except... 語句用于捕獲異常 及 對(duì)異常的處理。這樣程序在發(fā)生異常時(shí),可針對(duì)性的做出處理,避免程序的中斷~,try...except... 語句的語法如下:
try:
可能發(fā)生異常的語句塊
except [異常類型1]:
處理異常1的語句
except [異常類型2]:
處理異常2的語句
示例:
try:
a = 1/0
except ZeroDivisionError:
print('除數(shù)不能為0')
?
try...except... 語句的工作原理如下:
try:
num = int(input("Enter a number: ")) # 這里可能會(huì)發(fā)生 ValueError 異常
a = 1/0
except ZeroDivisionError:
print('除數(shù)不能為0')
對(duì)于可能會(huì)先發(fā)生的 ValueError 異常,異常類型和 except 關(guān)鍵字后面的異常不匹配,那么這個(gè) 異常 將不會(huì)被 這個(gè)except 捕獲,于是這個(gè)異常就會(huì)被傳遞到外部~,結(jié)果輸出如下:
Enter a number: abc
Traceback (most recent call last):
File "...test.py", line 9, in <module>
num = int(input("Enter a number: ")) # 這里可能會(huì)發(fā)生 ValueError
ValueError: invalid literal for int() with base 10: 'abc'
?
這個(gè)時(shí)候,可以使用多個(gè) except 來捕獲異常:
try:
num = int(input("Enter a number: ")) # 這里可能會(huì)發(fā)生 ValueError
a = 1/0
except ZeroDivisionError:
print('除數(shù)不能為0')
except ValueError:
print('請(qǐng)輸入數(shù)字~')
# 結(jié)果輸出:
Enter a number: abc
請(qǐng)輸入數(shù)字~
當(dāng)然也可以使用一個(gè)萬能異常 Exception 來處理。由于內(nèi)置異常和自定義異常都直接或間接地繼承自 Exception,所以 Exception 可以用來匹配任何異常。這樣做的優(yōu)勢在于 可以針對(duì)所有的異常統(tǒng)一進(jìn)行捕獲,缺點(diǎn)在于 不能針對(duì)指定的異常做出相應(yīng)的處理,而是統(tǒng)一使用一種方式進(jìn)行處理~
try:
num = int(input("Enter a number: "))
a = 1/0
except Exception:
pass
?
在實(shí)際的應(yīng)用中,一般這兩種方式會(huì)被結(jié)合使用:針對(duì)指定的那么幾個(gè)異常分別進(jìn)行捕獲并做相應(yīng)的處理,剩下的所有異常都統(tǒng)一使用 Exception 來捕獲~
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print(err)
except ValueError:
print("數(shù)據(jù)類型無法轉(zhuǎn)換")
except Exception:
print('Unexpected error')
最后的 Exception異常名 也可以省略不寫(默認(rèn)就是 Exception )
except:
print('Unexpected error')
異常發(fā)生時(shí),都會(huì)有關(guān)于這個(gè)異常的具體描述信息,異常的描述信息可通過 as 關(guān)鍵字獲取,這個(gè)在上述示例中已經(jīng)有使用~
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print(err)
# 若文件不存在,或有如下輸出:
[Errno 2] No such file or directory: 'myfile.txt'
else 為可選字句,放在 except 字句后面,若 try 語句塊中沒有異常發(fā)生,則會(huì)執(zhí)行else 語句塊中的代碼~
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print(err)
else:
f.close() # try 語句塊正常執(zhí)行完成后,關(guān)閉打開的文件
finally 也為可選字句,放在所有語句塊的最后。不管 try 語句塊中是否觸發(fā)異常,都會(huì)執(zhí)行 finally 語句塊中的代碼。finally 語句塊中的代碼一般都用于 關(guān)閉系統(tǒng)資源,例如關(guān)閉文件,關(guān)閉數(shù)據(jù)庫連接等~
def connDB():
try:
conn = pymysql.connect(host=HOST, user=USER, password=PASSWD, database=DATEBASE, charset='utf8', cursorclass=pymysql.cursors.DictCursor)
return conn
except Exception:
logger.error("can not connect to database!")
exit()
db = connDB()
try:
...
pass
except:
...
pass
finally:
db.close()
?
在操作文件時(shí),還可以使用 with...as... 語句來自動(dòng)關(guān)閉文件,即不管 with語句塊 中是否觸發(fā)異常,with語句塊執(zhí)行完畢后都會(huì)自動(dòng)關(guān)閉文件~
try:
f = open('myfile.txt', mode='r')
a = 1/0
except Exception:
print(f.closed) # False,當(dāng) try語句塊中發(fā)生異常,文件沒有被關(guān)閉
##############
try:
with open('myfile.txt', mode='r') as f:
a = 1 / 0
except Exception:
print(f.closed) # True,文件已經(jīng)自動(dòng)關(guān)閉
raise語句用于手動(dòng)觸發(fā)異常,觸發(fā)的異??梢酝ㄟ^傳遞參數(shù)說明異常的原因,例如:
>>> raise IndexError('lst out of range')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: lst out of range
?
在 except語句塊中,若不想對(duì)捕獲的異常進(jìn)行處理,則可以使用 raise語句 重新觸發(fā)異常,由外層的 try語句來進(jìn)行處理~
try:
raise ZeroDivisionError('abc')
except ZeroDivisionError:
print('除數(shù)為0')
raise # 更簡單的寫法,重新觸發(fā)捕獲到的異常
assert語法:
assert expression
assert 關(guān)鍵字根據(jù)后面的表達(dá)式的真假來確定程序是否繼續(xù)往下執(zhí)行。若表達(dá)式返回為True,則程序繼續(xù)往下執(zhí)行,若為False,則觸發(fā) AssertionError 異常~
print('start...')
assert 1 == 1
print('end...')
# 輸出結(jié)果:
start...
end...
################
print('start...')
assert 1 == 2
print('end...')
# 輸出結(jié)果:
start...
Traceback (most recent call last):
File ".../test.py", line 17, in <module>
assert 1 == 2
AssertionError
通過繼承 Exception 類來創(chuàng)建自定義的異常;自定義異常應(yīng)該盡量保持異常類的簡單,一般自定義異常僅用于提取特有的錯(cuò)誤信息~。自定義異常示例如下:
class MyError(Exception):
def __init__(self, ErrorInfo):
Exception.__init__(self)
self.errorinfo=ErrorInfo
def __str__(self):
return self.errorinfo
?
注意:自定義的異常類只能通過 raise關(guān)鍵字 來手動(dòng)觸發(fā)。
使用 traceback 關(guān)鍵字追蹤異常,需要導(dǎo)入 traceback 模塊(import traceback)。
import traceback
try:
f = open('myfile.txt', mode='r')
a = 1/0
except Exception:
traceback.print_exc()
logger.error(traceback.format_exc()) #使用日志模塊記錄 異常的詳細(xì)信息,或使用 traceback.print_exc(file=path) 記錄到指定文件
# 輸出信息如下:
Traceback (most recent call last):
File "/Users/luyi/PycharmProjects/untitled/day26/test.py", line 12, in <module>
a = 1/0
ZeroDivisionError: division by zero
這里異常信息的輸出和不捕獲異常時(shí)候系統(tǒng)的輸出一致,其實(shí) traceback.print_exc() 函數(shù)調(diào)用了sys.exc_info() 函數(shù)來完成 異常信息的輸出,traceback.print_exc()的源碼如下:
def print_exc(limit=None, file=None):
"""Shorthand for 'print_exception(sys.exc_type, sys.exc_value, sys.exc_traceback, limit, file)'.
(In fact, it uses sys.exc_info() to retrieve the same information
in a thread-safe way.)"""
if file is None:
file = sys.stderr
try:
etype, value, tb = sys.exc_info() # 調(diào)用了 sys.exc_info() 函數(shù)
print_exception(etype, value, tb, limit, file)
finally:
etype = value = tb = None
.................^_^
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。