1.例外與例外處理
??例外就是程式中的錯誤,正常情況下程式是自上而下逐行執行的,當遇到例外時,就會報錯退出執行;
??例外處理就是在程式中可能出錯的地方進行提前預捕獲,并將例外部分的程式進行修正使得程式正常執行,
2.例外的語法
??利用try ... except ... 關鍵字
# 以字串的upper方法為例
def new_upper(str_data):
new_str = str_data.upper()
return new_str
# 輸入正常的字串,程式執行正常,回傳結果正常
new_str = new_upper('test_str')
print(new_str)
'''
TEST_STR
'''
# 輸入非字串型別,程式會報錯
new_str2 = new_upper(1)
print(new_str2)
'''
Traceback (most recent call last):
File "D:\python_exercise\try_except.py", line 15, in <module>
new_str2 = new_upper(1)
File "D:\python_exercise\try_except.py", line 6, in new_upper
new_str = str_data.upper()
AttributeError: 'int' object has no attribute 'upper'
'''
# 接上,此時可以通過try...except...提前捕獲例外
def new_upper(str_data):
new_str = 'init_value'
try:
new_str = str_data.upper()
print('try中代碼繼續執行')
except:
print('傳入的字串引數可能有誤,請檢查!')
print('整個方法繼續執行')
return new_str
# 傳入的資料正確時
new_str = new_upper('test_str')
print(new_str)
# try模塊中沒有例外出現,則不會執行except模塊中代碼;程式自上而下正常執行
'''
try中代碼繼續執行
整個方法繼續執行
TEST_STR
'''
# 傳入的資料出錯時,會立即執行except模塊中代碼,且try中后續代碼不再執行,整個方法的后續代碼會繼續執行
new_str = new_upper(1)
print(new_str)
'''
傳入的字串引數可能有誤,請檢查!
整個方法繼續執行
init_value
'''
3.保存并處理報錯資訊
??上面的例子中,在例外出現時,捕獲后做了自定義的處理,沒有保留或列印真正的報錯資訊;
??可以在except模塊中,捕獲并拋出真正的錯誤資訊;
# 有兩種處理方式
# 一種是不知道會出現什么錯誤,用Exception做通用的例外捕獲
# 以1不能除0為例, 正常情況下,程式執行例外,會直接報錯
1 / 0
'''
Traceback (most recent call last):
File "D:\python_exercise\try_except.py", line 5, in <module>
1 / 0
ZeroDivisionError: division by zero
'''
# 此時,想拿到Error資訊,捕獲例外書寫方法如下
def test():
try:
1 / 0
except Exception as e: # as e 給例外資訊起個別名e(e可以隨意起名,一般大家都習慣寫e)
print(e)
test()
'''
division by zero
'''
# 另一種是提前知道可能出現的例外型別,可直接按已知例外型別捕獲
# 例如例子中已知1/0時的ZeroDivisionError
def test2():
try:
1 / 0
except ZeroDivisionError as e:
print(e)
test2()
'''
division by zero
'''
"""
通用捕獲方法,程式執行時需要去例外型別庫中找一下報錯型別,再去拋出;可能在性能上比指定例外型別差一些,但也可忽略不計;
通用捕獲方法,所有例外情況某一種出現都會被拋出,但指定錯誤型別的方法,當出現其它錯誤型別時,則不會被拋出,程式依舊報錯;
所以兩種方式可以按需使用,
"""
# 指定錯誤型別時,若出現其它錯誤,程式仍會報錯
def test3():
try:
3/4
test_str = 3
test_str.upper()
except ZeroDivisionError as e:
print(e)
test3()
# 此時程式仍會報錯
'''
Traceback (most recent call last):
File "D:\python_exercise\try_except.py", line 51, in <module>
test3()
File "D:\python_exercise\try_except.py", line 47, in test3
test_str.upper()
AttributeError: 'int' object has no attribute 'upper'
'''
??上面的例子中,按型別捕獲例外時,是可以同時捕獲多種型別的;
# 多個例外捕獲,依然有兩種寫法,此時代碼中出現某一種錯誤后就不再進行后續捕獲了
# 一種是可以添加多個except模塊
def test():
try:
1/0
new_str = 2
new_str.upper()
except ZeroDivisionError as e:
print(e)
except AttributeError as e:
print(e)
print('end')
test()
'''
division by zero
end
'''
# 另一種是寫在except元組中
def test2():
try:
1/0
new_str = 2
new_str.upper()
except (AttributeError, ZeroDivisionError) as e:
print(e)
print(type(e)) # 此時要注意下e不是字串,是錯誤型別對應的類
print(dir(e)) # 列印e的所有可用方法
print(str(e)) # 有其它需求,可以轉化成字串
print('end')
test2()
'''
division by zero
<class 'ZeroDivisionError'>
['__cause__', '__class__', '__context__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__suppress_context__', '__traceback__', 'args', 'with_traceback']
division by zero
end
'''
??
4.了解常用的例外型別
??Exception 通用例外型別(基類,是所有例外型別的父類)
??ZeroDivisonError 不能整除0
??AttributeError 物件沒有這個屬性(或方法)
??IOError 輸入輸出操作失敗 (用于檔案讀寫)
??IndexError 沒有當前的索引 (串列、元組中使用)
??KeyError 沒有這個鍵值(key)字典中使用
??NameError 沒有這個變數 (未初始化物件)
??SyntaxError python語法錯誤
??SystemError 解釋器的系統錯誤 (少見)
??ValueError 傳入的引數錯誤 (函式傳參出錯)
??TypeError 函式傳參型別錯誤
def test(a):
print(a)
test() # 需要一個必傳引數(位置引數),但這里是按默認引數有值傳遞的,會報錯
'''
Traceback (most recent call last):
File "D:\python_exercise\try_except.py", line 57, in <module>
test()
TypeError: test() missing 1 required positional argument: 'a'
'''
try:
test()
except TypeError as e:
print(e)
'''
test() missing 1 required positional argument: 'a'
'''
5.finally的功能和用法
??finally是try...except后的額外操作,無論是否發生例外,都會執行finally代碼塊;
def upper(str_data):
try:
new_str = str_data.upper()
print('try模塊執行')
return new_str
except AttributeError as e:
print(e)
finally:
print('finally模塊執行')
return 'finally'
# 呼叫無例外時
re = upper('test')
print(re)
'''
try模塊執行
finally模塊執行
finally
'''
# 可以看到無例外拋出時,執行try模塊后,會繼續執行finally模塊
# 且當try中有return回傳時,也會再執行finally模塊,且當finally中也有return時、最終return結果被finally的覆寫
# 呼叫出現例外時
re2 = upper(3)
print(re2)
'''
'int' object has no attribute 'upper'
finally模塊執行
finally
'''
# 可以看到遇到例外后,直接執行了expect模塊
# 執行except模塊后,依然執行finally模塊
# 有時也會只有try...finally一起使用
# 此時出現例外后,不會被捕獲,正常報錯,但仍會執行finally模塊代碼
def test():
try:
1/0
finally:
print('finally執行')
test()
'''
Traceback (most recent call last):
File "D:\python_exercise\try_except.py", line 119, in <module>
test()
File "D:\python_exercise\try_except.py", line 115, in test
1/0
ZeroDivisionError: division by zero
finally執行
'''
# 此時如果在finally中做return操作
def test2():
try:
print('try1')
1/0
print('try2')
finally:
print('finally執行')
return 'finally re'
re = test2()
print(re)
'''
try1
finally執行
finally re
'''
# 可以看到遇到例外后未拋出程式例外
# 直接正常執行了finally模塊code
??
6.自定義例外與拋出例外
??之前我們看到的Exception, NameError, KeyError等錯誤型別,都是python中自帶的拋出例外型別;
??在平常業務開發中,我們也可以主動定義拋出一些例外,更好的服務于業務;
'''
使用自定義拋出例外函式 --raise
將資訊以報錯的形式拋出
'''
def test(number):
if number == 50:
raise ValueError('數字不能是50') # raise后的exception型別可以自選
return number
re = test(100)
print(re) # 100
re2 = test(50)
print(re2)
'''
Traceback (most recent call last):
File "D:\python_exercise\try_except.py", line 165, in <module>
re2 = test(50)
File "D:\python_exercise\try_except.py", line 159, in test
raise ValueError('數字不能是50') # raise后的exception型別可以自選
ValueError: 數字不能是50
'''
# 自定義的錯誤型別,也是可以通過try...except捕獲到的
try:
test(50)
except Exception as e:
print(e)
'''
數字不能是50
'''
'''
上述例子中valueError正常是表示引數傳遞引數錯誤的錯誤型別,
和撰寫的函式中數字值錯誤并不是很貼切,此時可以使用通用的exception來拋出例外
'''
def test(number):
if number == 100:
raise Exception('數值錯誤,請檢查')
return number
re = test(100)
print(re)
'''
Traceback (most recent call last):
File "D:\python_exercise\try_except.py", line 194, in <module>
re = test(100)
File "D:\python_exercise\try_except.py", line 191, in test
raise Exception('數值錯誤,請檢查')
Exception: 數值錯誤,請檢查
'''
'''
此時還可以自己撰寫一個例外型別類,更貼切的描述例外
'''
# 需繼承Exception基類
class NumberLimitError(Exception):
def __init__(self, message):
self.message = message
def test2(number):
if number == 100:
raise NumberLimitError('數值錯誤,請檢查')
return number
test2(100)
'''
Traceback (most recent call last):
File "D:\python_exercise\try_except.py", line 219, in <module>
test2(100)
File "D:\python_exercise\try_except.py", line 216, in test2
raise NumberLimitError('數值錯誤,請檢查')
__main__.NumberLimitError: 數值錯誤,請檢查
'''
try:
test2(100)
except NumberLimitError as e:
print(e)
'''
數值錯誤,請檢查
'''
# 順便提下try...except...else
# 無例外出現時,走else邏輯
try:
test2(50)
except NumberLimitError as e:
print(e)
else:
print('無例外發生')
finally:
print('finally code')
'''
無例外發生
finally code
'''
7.斷言
??斷言是對一個運算式進行判斷,在運算式是false時觸發例外;
??斷言關鍵字assert;assert expresion, message ; (expression是要判斷的運算式,結果是bool型別;message是遇到錯誤要拋出的例外資訊)
??斷言與raise功能類似,相當于對raise的簡化寫法(使用raise時,會先書寫if陳述句進行判斷、再看是否raise拋出例外,assert一行代碼就可以搞定這些功能)
assert 1 == 1 # 條件陳述句為True,正常執行
assert 1 > 2 # 條件陳述句為False, 會觸發報錯
"""
Traceback (most recent call last):
File "D:\python_exercise\try_except.py", line 252, in <module>
assert 1 > 2
AssertionError
"""
# 此時未指定報錯資訊,只拋出AssertionError例外,未列印資訊
import sys
print(sys.platform) # win32
assert ('win32' not in sys.platform), '當前PC型號判斷有誤'
"""
Traceback (most recent call last):
File "D:\python_exercise\try_except.py", line 262, in <module>
assert ('win32' not in sys.platform), '當前PC型號判斷有誤'
AssertionError: 當前PC型號判斷有誤
"""
????
8.代碼bug除錯
??bug是程式中的錯誤,沒有提前進行例外捕獲,以至于程式報錯,導致程式崩潰;
??平常開發中代碼量較大時,可能不好定位例外的位置,比較耗時,有兩種方式可以幫助我們除錯程式找到錯誤;
??一種是可以借助print列印資訊,輔助定位;
a = 1
print('執行到這里1')
b = 2
print('執行到這里2')
c = 3
print('執行到這里3')
print(a, b, c, d)
'''
執行到這里1
執行到這里2
執行到這里3
Traceback (most recent call last):
File "D:\python_exercise\try_except.py", line 276, in <module>
print(a, b, c, d)
NameError: name 'd' is not defined. Did you mean: 'id'?
'''
# 可以看到'執行到這里3'已成功列印,說明錯誤出現在'執行到這里3'下一行
# (目前代碼量較少,程式已直接列印出了出錯的位置,代碼呼叫層級較多時,除錯效果會更大些)
??另一種是可以借助pycharm的debug功能,利用斷點除錯程式;
??仍然使用相同的代碼,在猜測引起報錯位置、想要暫停的地方開頭點擊一下,形成斷點;
??
??點擊pycharm右上角的debug按鈕,開始執行debug模式;
??
??開始debug執行,可以看到每一步已經自動幫我們標注了變數值變化資訊(這里的a: 1), 視窗下方會出現debug操作窗;
??
??發現目前沒出現錯誤,想繼續執行可以點擊底部彈窗的執行按鈕,會執行后續所有的代碼(如果后續仍有斷點,則執行到下一個斷點)
??
??可以看到報錯位置已經幫我們標注出來了,代碼呼叫層級較多時,可以幫助我們分段除錯代碼,比較方便;
??
總結
??
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/539306.html
標籤:Python
上一篇:pdf和圖片的處理一記
