python的異常處理


異常處理

什么是異常?

        首先要清楚,什么是異常,異常就是程序運行時發生錯誤的信號(在程序出現錯誤時,則會產生一個異常,若程序沒有處理它,則會拋出該異常,程序的運行也隨之終止),在python中,錯誤觸發的異常如下

        異常是由錯誤觸發的,那么錯誤有哪些情況呢?

1.語法錯誤:

#語法錯誤示范一
else
#語法錯誤示范二
def test:
    pass
#語法錯誤示范三
class Cal
    pass
#語法錯誤示范四
print(hello

1.語法錯誤(這種錯誤,根本過不了python解釋器的語法檢測,必須在程序執行前就改正)
View Code

 2.邏輯錯誤

# res=1/0
# l=[1,2]
# l[10]

# age=input('>>: ')
# age=int(age)
# res=1/0

# l=[]
# l[10000]

# dic={}
# dic['name']

# class Foo:
#     pass
# Foo.x

2.邏輯錯誤示范
View Code

異常的種類

          在平時編碼過程中,常見的異常有以下這些:

AttributeError 試圖訪問一個對象沒有的樹形,比如foo.x,但是foo沒有屬性x
IOError 輸入/輸出異常;基本上是無法打開文件
ImportError 無法引入模塊或包;基本上是路徑問題或名稱錯誤
IndentationError 語法錯誤(的子類) ;代碼沒有正確對齊
IndexError 下標索引超出序列邊界,比如當x只有三個元素,卻試圖訪問x[5]
KeyError 試圖訪問字典里不存在的鍵
KeyboardInterrupt Ctrl+C被按下
NameError 使用一個還未被賦予對象的變量
SyntaxError Python代碼非法,代碼不能編譯(個人認為這是語法錯誤,寫錯了)
TypeError 傳入對象類型與要求的不符合
UnboundLocalError 試圖訪問一個還未被設置的局部變量,基本上是由於另有一個同名的全局變量,
導致你以為正在訪問它
ValueError 傳入一個調用者不期望的值,即使值的類型是正確的

        當然,還有其他異常,這里就不做過多演示。出現異常,我們肯定想到要處理,不然程序就直接報錯崩潰了。其實我們一直在處理異常,只是沒有發現,比如要判斷你輸入的內容是不是數字,我們以前是這么判斷的:

age = input('請輸入你的年齡: ').strip()
if age.isdigit():
    int(age)      #這是主邏輯
elif age.isspace():
    print('輸入的是空格!')
elif len(age) == 0 :
    print('沒有輸入內容')
else:
    print('其他異常!')

>>>請輸入你的年齡: dasdasf
>>>其他異常!

        在這里if就是在處理異常,但是,如果我還有其他程序也要運行,那就要寫成這樣了:

age = input('請輸入你的年齡: ').strip()
if age.isdigit():
    int(age)      #這是主邏輯
elif age.isspace():
    print('輸入的是空格!')
elif len(age) == 0 :
    print('沒有輸入內容')
else:
    print('其他異常!')
    
num = input('請輸入你的編號: ').strip()
if num.isdigit():
    int(num)      #這是主邏輯
elif num.isspace():
    print('輸入的是空格!')
elif len(num) == 0 :
    print('沒有輸入內容')
else:
    print('其他異常!')
View Code

       這時候,你會發現,程序寫的很長,可讀性差,如果有十個這樣的輸入,那這個程序就沒法看了,這時候,python提供了一種異常處理的方法try...except...

part1 基本語法

try:
    被執行的邏輯
except 異常名稱:
    如果try中的邏輯出現異常,就執行這段邏輯

        現在用這套方法來處理上面的異常,看看效果怎么樣:

try:
    age = input('請輸入你的年齡: ').strip()
    int(age)

    num = input('請輸入你的編號: ').strip()
    int(num)
except ValueError as e:    #根據報錯知道錯誤類型是ValueError
    print(e)


>>>請輸入你的年齡: 23
>>>請輸入你的編號: dwqd
>>>invalid literal for int() with base 10: 'dwqd'
View Code

        這樣一看代碼簡潔了很多啊,效果很完美

part2 異常只能用來處理指定的異常情況,其他情況不會處理

       我們可以試一下,把錯誤類型改成別的,看看會怎樣:

try:
    age = input('請輸入你的年齡: ').strip()
    int(age)

    num = input('請輸入你的編號: ').strip()
    int(num)
except IndexError as e:    
    print(e)

>>>請輸入你的年齡: ffq
Traceback (most recent call last):
  File "C:/Users/pengfy/PycharmProjects/untitled/錯誤與異常/錯誤與異常.py", line 26, in <module>
    int(age)
ValueError: invalid literal for int() with base 10: 'ffq'
View Code

        看來錯誤類型還要對應才行。

part3 多分支

try:
    age = input('請輸入你的年齡: ').strip()
    int(age)

    num = input('請輸入你的編號: ').strip()
    int(num)

    l=[]
    l[10000]

    dic={}
    dic['name']

except ValueError as e:    
    print(e)
except IndexError as e:
    print(e)
except KeyError as e:
    print(e)

print('我繼續執行')

>>>請輸入你的年齡: 12
>>>請輸入你的編號: 321
>>>list index out of range
>>>我繼續執行
View Code

         多加幾個except,就可以處理不同分支的異常了,這個和if...else...里面的elif很類似吧,現在就有疑問了,有沒有像if...else...里面else這樣的萬能處理呢,答案是肯定的。

part4 萬能異常

       為了避免寫太多異常類型,或者一些不清楚的錯誤類型不知道怎么寫,那么可以用Exception:

try:
    age = input('請輸入你的年齡: ').strip()
    int(age)

    num = input('請輸入你的編號: ').strip()
    int(num)

    dic={}
    dic['name']

    l=[]
    l[10000]

except Exception as e:
    print(e)

print('我繼續執行')

>>>請輸入你的年齡: 213
>>>請輸入你的編號: 23
>>>'name'
>>>我繼續執行
View Code

        這時候,有人就會覺得,萬能異常這么厲害,我還要寫什么其他異常的,全部用這個不就好啦?這個怎么說呢,要分兩點來看吧:

1.如果你想要的效果是,無論什么異常,你都直接無視或者說用一種處理機制,那么就直接用吧,沒問題,

2.如果你要根據異常類型處理不同機制,那還得用多分支的方式,

       當然,你可以結合多分支和萬能異常一起使用啊,這樣多分支的健壯性會更好

part5 異常的其他結構

      下面來看看異常處理的其他結構:

try:
    age = input('請輸入你的年齡: ').strip()
    int(age)

    num = input('請輸入你的編號: ').strip()
    int(num)

    # l=[]
    # l[10000]
    #
    # dic={}
    # dic['name']

except ValueError as e:
    print('566')
except IndexError as e:
    print('435')
except KeyError as e:
    print('755')
# except Exception as e:
#     print(e)
else:
    print('try里面沒有異常出現,執行我')
finally:
    print('不管有沒有異常,我都執行,我一般是做清理工作')

print('我繼續執行')

>>>請輸入你的年齡: 12
>>>請輸入你的編號: 21
>>>try里面沒有異常出現,執行我
>>>不管有沒有異常,我都執行,我一般是做清理工作
>>>我繼續執行
View Code
try:
    age = input('請輸入你的年齡: ').strip()
    int(age)

    num = input('請輸入你的編號: ').strip()
    int(num)

    l=[]
    l[10000]

    dic={}
    dic['name']

except ValueError as e:
    print('566')
except IndexError as e:
    print('435')
except KeyError as e:
    print('755')
# except Exception as e:
#     print(e)
else:
    print('try里面沒有異常出現,執行我')
finally:
    print('不管有沒有異常,我都執行,我一般是做清理工作')

print('我繼續執行')

>>>請輸入你的年齡: 32
>>>請輸入你的編號: 13
>>>435
>>>不管有沒有異常,我都執行,我一般是做清理工作
>>>我繼續執行
View Code

       看完兩個例子,可以知道這里面的else和if...else...里面的完全是兩回事,主要不要混淆。當try沒有異常時,else里面的邏輯才會執行,而finally不論在什么情況下都會執行,一般用來做清理工作,比如說你在try里面打開了一個問題,然后中途出現異常了,那么你的文件還在內存中,這時候你可以在finally里面關閉文件。

part6  主動觸發異常

      我們學過主動觸發異常用的是raise,下面看一下能不能捕獲:

try:
    raise TypeError('打印錯誤')
except TypeError as e:
    print(e)

>>>打印錯誤
View Code

part7 自定義異常

     如果你想自定義一個異常,也是可以的。異常是什么,就是一個類嘛,那我們就定義一個異常類看看:

class Pengfyexception():
    def __init__(self,msg):
        self.msg = msg      #報錯打印的內容

try:
    raise Pengfyexception('自定義的異常')
except Pengfyexception as e:
    print(e)

>>> Traceback (most recent call last):
  File "C:/Users/pengfy/PycharmProjects/untitled/錯誤與異常/錯誤與異常.py", line 103, in <module>
    raise Pengfyexception('自定義的異常')
TypeError: exceptions must derive from BaseException
View Code

      報錯了,看錯誤提示,再看看type錯誤是怎么寫的,原來要繼承一個叫BaseException的類,再試一下:

class Pengfyexception(BaseException):
    def __init__(self,msg):
        self.msg = msg      #報錯打印的內容

try:
    raise Pengfyexception('自定義的異常')
except Pengfyexception as e:
    print(e)


>>>自定義的異常
View Code

      完美了,成了。

part8 斷言

     斷言可以說就是if的一種簡寫,直接看例子吧:

def test():
    """一萬行代碼得到ret"""
    ret = 1
    return ret

res = test()
assert res == 1
"""繼續執行下面的代碼"""
View Code

    如果判斷不正確:

def test():
    """一萬行代碼得到ret"""
    ret = 1
    return ret

res = test()
assert res == 2
"""繼續執行下面的代碼"""


>>>Traceback (most recent call last):
  File "C:/Users/pengfy/PycharmProjects/untitled/錯誤與異常/錯誤與異常.py", line 122, in <module>
    assert res == 2
AssertionError
View Code

    這個完全可以用if寫:

def test():
    """一萬行代碼得到ret"""
    ret = 1
    return ret

res = test()
# assert res == 1
if res != 1:
    raise AssertionError
# """繼續執行下面的代碼"""
View Code

    效果完全一樣

part9 try...except...的好處和用法:

      try...except...就是取代了if的那種方法,讓你的代碼在保證可讀性的情況下,還增強了健壯性,提高了容錯率,使用這種方法:

1.把錯誤處理和你的主邏輯分開了

2.代碼更容易組織,更清晰,復雜的任務更容易實現

3.更安全了,不會因為一些小錯誤導致程序崩潰

        但是要清楚的一點是,if和try...except...都是python中處理異常的方法,不要學了try就說if和異常處理沒有關系了。其次,學完這個后發現try...except...很強大,是不是每一段代碼都可以加這個處理異常,就不用管報錯了,這是肯定不行的,try...except...還是要慎重使用,首先try...except是你附加給你的程序的一種異常處理的邏輯,與你的主要的工作是沒有關系的,這種東西加的多了,會導致你的代碼可讀性變差,然后異常處理本就不是你混亂邏輯的保姆,只有在錯誤發生的條件無法預知的情況下,才應該加上try...except

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM