第八章 異常

第八章 異常

異常事件可能是錯誤(如試圖除以零),也可能是通常不會發生的事情。
Python提供功能強大的替代解決方案——異常處理機制。

異常是什么?

Python使用異常對象來表示異常狀態,并在遇到錯誤時引發異常。異常對象未被處理或捕 獲)時,程序將終止并顯示一條錯誤消息(traceback)。

1 / 0
'''
ZeroDivisionError  Traceback (most recent call last)
<ipython-input-146-05c9758a9c21> in <module>()
----> 1/0
ZeroDivisionError: division by zero
'''

事實上,每個異常都是某個類(這里是ZeroDivisionError)的實例.

讓事情沿你指定的軌道出錯

raise 語句

要引發異常,可使用raise語句,并將一個類(必須是Exception的子類)或實例作為參數。將類作為參數時,將自動創建一個實例。

在第一個示例(raise Exception)中,引發的是通用異常,沒有指出出現了什么錯誤。
在第二個示例中,添加了錯誤消息beyondhuangjiaju。

raise Exception
'''
Exception  Traceback (most recent call last)
<ipython-input-147-fca2ab0ca76b> in <module>()
----> raise ExceptionException: 
'''
raise Exception('beyondhuangjiaju')
'''
Exception  Traceback (most recent call last)
<ipython-input-149-dfdac40c1137> in <module>()
----> raise Exception('beyondhuangjiaju')Exception: beyondhuangjiaju
'''raise ArithmeticError
'''
ArithmeticError  Traceback (most recent call last)
<ipython-input-150-36d9a98b39c2> in <module>()
----> raise ArithmeticErrorArithmeticError: 
'''
raise ArithmeticError("beyondhuangjiaju")
'''
ArithmeticError  Traceback (most recent call last)
<ipython-input-151-a6ed875c1de3> in <module>()
----> 1 raise ArithmeticError("beyondhuangjiaju")ArithmeticError: beyondhuangjiaju
'''

一些內置的異常類如下表所示:

類名描述
Exception幾乎所有的異常類都是從它派生而來的
AttributeError引用屬性或給它賦值失敗時引發
OSError操作系統不能執行指定的任務(如打開文件)時引發,有多個子類
IndexError使用序列中不存在的索引時引發,為LookupError的子類
KeyError使用映射中不存在的鍵時引發,為LookupError的子類
NameError找不到名稱(變量)時引發
SyntaxError代碼不正確時引發
TypeError將內置操作或函數用于類型不正確的對象時引發
ValueError將內置操作或函數用于這樣的對象時引發:其類型正確但包含的值不合適
ZeroDivisionError在除法或求模運算的第二個參數為零時引發

自定義的異常類

如何創建異常類呢?
就像創建其他類一樣,但務必直接或間接地繼承Exception(這意味著從任何內置異常類派生都可以)。
當然,如果你愿意,也可在自定義異常類中添加方法。

class SomeCustomBeyondException(Exception): pass

捕獲異常

異常比較有趣的地方是可對其進行處理,通常稱之為捕獲異常
可使用try/except語句。

try: x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) print(x / y) 
except ZeroDivisionError: print("The second number can't be zero!")'''
Enter the first number: 5
Enter the second number: 0
The second number can't be zero!
'''

不用提供參數

來看一個能夠“抑制”異常ZeroDivisionError的計算器類。如果啟用了這種功能,計算器將打印一條錯誤消息,而不讓異常繼續傳播。在與用戶交互的會話中使用這個計算器時,抑制異常很有用;但在程序內部使用時,引發異常是更佳的選擇(此時應關閉“抑制”功能)。

class MuffledCalculator: muffled = False def calc(self, expr): try: return eval(expr) except ZeroDivisionError: if self.muffled: print('Division by zero is illegal') else: raisecalculator = MuffledCalculator()
calculator.calc('10 / 2')#結果為:5.0
calculator.calc('10 / 0')#報錯!!!calculator.muffled = True
calculator.calc('10 / 0') #結果為:Division by zero is illegal

如果無法處理異常,在except子句中使用不帶參數的raise通常是不錯的選擇,但有時你可能想引發別的異常。
在這種情況下,導致進入except子句的異常將被作為異常上下文存儲起來,并出現在最終的錯誤消息中。

try:1/0
except ZeroDivisionError:raise ValueError
#在處理上述異常時,引發了另一個異常:'''
ZeroDivisionError  Traceback (most recent call last)
<ipython-input-160-14da06562399> in <module>()1 try:
----> 2     1/03 except ZeroDivisionError:ZeroDivisionError: division by zeroDuring handling of the above exception, another exception occurred:ValueError  Traceback (most recent call last)
<ipython-input-160-14da06562399> in <module>()2     1/03 except ZeroDivisionError:
----> 4     raise ValueErrorValueError: 
'''#可使用raise ... from ...語句來提供自己的異常上下文,也可使用None來禁用上下文。
try:1/0
except ZeroDivisionError:raise ValueError from None'''
ValueError  Traceback (most recent call last)
<ipython-input-161-f4775ad0e53d> in <module>()2     1/03 except ZeroDivisionError:
----> 4     raise ValueError from NoneValueError: 
'''

多個 except 子句

當你在輸入字符串的時候,此時會引發另一種異常,該程序中的except子句只捕獲ZeroDivisionError異常,這種異常將成為漏網之魚,導致程序終止。

try: x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) print(x / y) 
except ZeroDivisionError: print("The second number can't be zero!")'''
Enter the first number: 1999
Enter the second number: beyond
---------------------------------------------------------------------------
ValueError  Traceback (most recent call last)
<ipython-input-2-f93dbf72378b> in <module>()1 try:2     x = int(input('Enter the first number: '))
----> 3     y = int(input('Enter the second number: '))4     print(x / y)5 except ZeroDivisionError:ValueError: invalid literal for int() with base 10: 'beyond'
'''

為同時捕獲這種異常,可在try/except語句中再添加一個except子句。

try: x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) print(x / y) 
except ZeroDivisionError: print("The second number can't be zero!")
except TypeError:print("That wasn't a number,was it?")

一箭雙雕

如果要使用一個except子句捕獲多種異常,可在一個元組中指定這些異常
在except子句中,異常兩邊的圓括號很重要。

try: x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) print(x / y) 
except (ZeroDivisionError,TypeError,NameError): print("Your numbers were bogus ...")

在上述代碼中,如果用戶輸入字符串、其他非數字值或輸入的第二個數為零,都將打印同樣的錯誤消息。當然,僅僅打印錯誤消息幫助不大。

捕獲對象

try: x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) print(x / y) 
except (ZeroDivisionError,TypeError) as e: print(e)

這里的except子句捕獲兩種異常,但由于同時顯式地捕獲了對象本身,因此可將其打印出來,讓用戶知道發生了什么情況。

一網打盡

即使程序處理了好幾種異常,還是可能有一些漏網之魚。
如果用戶在提示時不輸入任何內容就按回車鍵,將出現一條錯誤消息,這種異常未被try/except語句捕獲,這理所當然,因為你沒有預測到這種問題,也沒有采取相應的措施。

try: x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) print(x / y) 
except: print("Something wrong happened...")'''
Enter the first number: 
Something wrong happened...
'''

像這樣捕獲所有的異常很危險,因為這不僅會隱藏你有心理準備的錯誤,還會隱藏你沒有考慮過的錯誤。
在大多數情況下,更好的選擇是使用except Exception as e并對異常對象進行檢查。
SystemExitKeyboardInterrupt從**BaseException(Exception的超類)**派生而來

萬事大吉

使用except Exception as e的小技巧在這個小型除法程序中打印更有用的錯誤消息。

while True:try:x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) value = x / yprint("x / y is",value)except Exception as e:print("Invalid input:",e)print('Please try again')else:break'''
Enter the first number: 1014
Enter the second number: beyond
Invalid input: invalid literal for int() with base 10: 'beyond'
Please try again
Enter the first number: 1202
Enter the second number: 
Invalid input: invalid literal for int() with base 10: ''
Please try again
Enter the first number: 1014
Enter the second number: 0522
x / y is 1.9425287356321839
'''

最后

最后,還有finally子句,可用于在發生異常時執行清理工作。這個子句是與try子句配套的。
finally子句非常適合用于確保文件或網絡套接字等得以關閉。
不管try子句中發生什么異常,都將執行finally子句。

x = None
try:x = 1 / 0
except NameError:print("Unknown variable")
else:print("That went well!")
finally:print('Cleaning up ...')del x

異常和函數

異常和函數有著天然的聯系。
如果不處理函數中引發的異常,它將向上傳播到調用函數的地方。
如果在那里也未得到處理,異常將繼續傳播,直至到達主程序(全局作用域)。
如果主程序中也沒有異常處理程序,程序將終止并顯示棧跟蹤消息。

def faulty():raise Exception('Something is wrong')def ignore_exception():faulty()def handle_exception():try:faulty()except:print('Exception handled')ignore_exception()
'''
Exception  Traceback (most recent call last)
<ipython-input-6-5ac314d0ac0c> in <module>()
----> 1 ignore_exception()<ipython-input-5-6806e60d5602> in ignore_exception()3 4 def ignore_exception():
----> 5     faulty()6 7 def handle_exception():<ipython-input-5-6806e60d5602> in faulty()1 def faulty():
----> 2     raise Exception('Something is wrong')3 4 def ignore_exception():5     faulty()Exception: Something is wrong
'''handle_exception()#結果為:Exception handled

faulty中引發的異常依次從faulty和ignore_exception向外傳播,最終導致顯示一條棧跟蹤消息。
調用handle_exception時,異常最終傳播到handle_exception,并被這里的try/except語句處理。

異常之禪

假設有一個字典,你要在指定的鍵存在時打印與之相關聯的值,否則什么都不做。

def describe_person(person):print('Description of',person['name'])print('Age:',person['age'])if 'occupation' in person:print('Occupation:',person['occupation'])

上面的這段代碼很直觀,但效率不高(雖然這里的重點是代碼簡潔),
因為它必須兩次查找occupation’鍵:
一次檢查這個鍵是否存在(在條件中),
另一次獲取這個鍵關聯的值,以便將其打印出來。

def describe_person(person):print('Description of',person['name'])print('Age:',person['age'])try:print('Occupation:',person['occupation'])except KeyError:pass

上面的這個函數直接假設存在’occupation’鍵。如果這種假設正確,就能省點事:直接獲取并打印值,而無需檢查這個鍵是否存在。如果這個鍵不存在,將引發KeyError異常,而except子句將捕獲這個異常。

檢查一個對象是否包含屬性write

try:obj.write
except AttributeError:print('The object is not writeable')
else:print('The object is writeable')

try子句只是訪問屬性write,而沒有使用它來做任何事情。
如果引發了AttributeError異常,說明對象沒有屬性write,否則就說明有這個屬性。

在很多情況下,相比于使用if/else,使用try/except語句更自然,也更符合Python的風格。

不那么異常的情況

如果你只想發出警告,指出情況偏離了正軌,可使用模塊warnings中的函數warn
警告只顯示一次。如果再次運行最后一行代碼,什么事情都不會發生。

from warnings import warn
warn('I like beyond band')
'''
D:\Anaconda3\lib\site-packages\ipykernel_launcher.py:2: UserWarning: I like beyond band
'''

如果其他代碼在使用你的模塊,可使用模塊warnings中的函數filterwarnings來抑制你發出的警告(或特定類型的警告),并指定要采取的措施,如"error"或"ignore"。

from warnings import filterwarnings
filterwarnings("ignore")
warn("Anyone out there?")
filterwarnings("error")
warn("Something is very wrong!")'''
UserWarning  Traceback (most recent call last)
<ipython-input-13-2678cd9c1908> in <module>()3 warn("Anyone out there?")4 filterwarnings("error")
----> 5 warn("Something is very wrong!")UserWarning: Something is very wrong!
'''

上述引發的異常為UserWarning。發出警告時,可指定將引發的異常(即警告類別),但必須是Warning的子類。如果將警告轉換為錯誤,將使用你指定的異常。另外,還可根據異常來過濾掉特定類型的警告。

from warnings import filterwarnings
filterwarnings("error")
warn("This function is really old...",DeprecationWarning)'''
DeprecationWarning  Traceback (most recent call last)
<ipython-input-14-db2d386b9ad9> in <module>()1 from warnings import filterwarnings2 filterwarnings("error")
----> 3 warn("This function is really old...",DeprecationWarning)DeprecationWarning: This function is really old...
'''
from warnings import filterwarnings
filterwarnings("ignore", category=DeprecationWarning)
warn("Another deprecation warning.", DeprecationWarning)
warn("Something else.")'''
UserWarning  Traceback (most recent call last)
<ipython-input-15-2ae8758ff90f> in <module>()1 filterwarnings("ignore", category=DeprecationWarning)2 warn("Another deprecation warning.", DeprecationWarning)
----> 3 warn("Something else.")UserWarning: Something else.
'''

小結

概念解釋
異常對象異常情況(如發生錯誤)是用異常對象表示的。對于異常情況,有多種處理方式;如果忽略,將導致程序終止。
引發異常可使用raise語句來引發異常。它將一個異常類或異常實例作為參數,但你也可提供兩個參數(異常和錯誤消息)。如果在except子句中調用raise時沒有提供任何參數,它將重新引發該子句捕獲的異常。
自定義的異常類你可通過從Exception派生來創建自定義的異常。
捕獲異常要捕獲異常,可在try語句中使用except子句。在except子句中,如果沒有指定異常類,將捕獲所有的異常。你可指定多個異常類,方法是將它們放在元組中。如果向except提供兩個參數,第二個參數將關聯到異常對象。在同一條try/except語句中,可包含多個except子句,以便對不同的異常采取不同的措施。
else子句除except子句外,你還可使用else子句,它在主try塊沒有引發異常時執行。
finally要確保代碼塊(如清理代碼)無論是否引發異常都將執行,可使用try/finally,并將代碼塊放在finally子句中。
異常和函數在函數中引發異常時,異常將傳播到調用函數的地方(對方法來說亦如此)。
警告警告類似于異常,但(通常)只打印一條錯誤消息。你可指定警告類別,它們是Warning的子類。

本章介紹的新函數

函數描述
warnings.filterwarnings(action,category=Warning, …)用于過濾警告
warnings.warn(message, category=None)用于發出警告

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/378318.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/378318.shtml
英文地址,請注明出處:http://en.pswp.cn/news/378318.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

hdu 1564 Play a game

對于本題&#xff0c;若要當前的 player 贏&#xff0c;剩下所走的步數必須是奇數步。所以對于每步的 player 所放棄的選擇的步數為偶數步。因此&#xff0c;對于整個 game 來說&#xff0c;所放棄的步數 m 為偶數步&#xff0c;設所走的步數為 k &#xff0c;則 n*n-1mk&…

【電設控制與圖像訓練題】【激光打靶】【opencv測試代碼以及效果】

博主聯系方式: QQ:1540984562 QQ交流群:892023501 群里會有往屆的smarters和電賽選手,群里也會不時分享一些有用的資料,有問題可以在群里多問問。 規則 激光槍自動射擊裝置(E題) 【本科組】 一、任務 設計一個能夠控制激光槍擊發、自動報靶及自動瞄準等功能的電子系統。該…

.NET 小結之內存模型

.NET 小結之內存模型 為什么要解.NET 的內存模型 在.NET下的內存管理、垃圾回收其實大部分不需要我們操心&#xff0c;因為大部分.NET已經幫我們做了&#xff0c;通常情況下也不需要考慮這些。但是如果想要了解一些.NET一些稍微“底層”的原理&#xff0c;如&#xff1a;“裝箱…

C ++ STL中的set :: upper_bound()函數

C STL set :: upper_bound()函數 (C STL set::upper_bound() function) set::upper_bound() function is a predefined function, it is used to get the upper bound of any element in a set. set :: upper_bound()函數是預定義的函數&#xff0c;用于獲取集合中任何元素的上…

c語言if不能判斷u8變量值,C語言變量名命規則.doc

C語言變量名命名規則一、程序風格&#xff1a;???????? 1、嚴格采用階梯層次組織程序代碼&#xff1a;???????? 各層次縮進的分格采用VC的缺省風格&#xff0c;即每層次縮進為4格&#xff0c;括號位于下一行。??? 要求相匹配的大括號在同一列&#xff0c;對…

【電設控制與圖像訓練題】【激光打靶】【openmv測試代碼以及效果】

9.4加入串口通訊,送出靶心坐標、激光坐標、激光所在環數、方位;加入防誤判操作 博主聯系方式: QQ:1540984562 QQ交流群:892023501 群里會有往屆的smarters和電賽選手,群里也會不時分享一些有用的資料,有問題可以在群里多問問。 目錄 規則坐標系代碼總結相關openmv使用文…

MVC3中的視圖文件

在MVC3中的視圖部分&#xff0c;Razor視圖引擎是與以往不同的地方之一&#xff0c;使用Razor的視圖文件再也不是以往的ASPX文件了&#xff0c;是cshtml文件&#xff0c;在新建視圖的時候也會發現增加多了幾類文件 由上到下分別是 MVC 3 Layout Page&#xff1a;與原來Web Form的…

第九章 魔法方法、特性和迭代器

第九章 魔法方法、特性和迭代器 構造函數 構造函數&#xff08;constructor&#xff09;&#xff0c;它其實就是初始化方法&#xff0c;只是命名為__init__。 構造函數不同于普通方法的地方在于&#xff0c;將在對象創建后自動調用它們。 在Python中&#xff0c;創建構造函數…

PHP 代碼 加密

PHP 代碼 加密 此加密方法支持任意PHP版 代碼如下: <?php function RandAbc($length""){//返回隨機字符串 $str"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; return str_shuffle($str); } $filenameindex.php; $T_k1RandAbc();//隨…

Python字符串| join()方法與示例

join() is an in-built method in Python and it is used to join elements of the list, string etc with the given str separator. join()是Python中的一種內置方法&#xff0c;用于通過給定的str分隔符連接列表&#xff0c;字符串等元素。 Note: Method is called with th…

C語言 鏈表拼接 PTA,PTA實驗 鏈表拼接 (20point(s))

本題要求實現一個合并兩個有序鏈表的簡單函數。鏈表結點定義如下&#xff1a;struct ListNode {int data;struct ListNode *next;};函數接口定義&#xff1a;struct ListNode *mergelists(struct ListNode *list1, struct ListNode *list2);其中list1和list2是用戶傳入的兩個按…

讀書筆記_Effective_C++_條款十九:設計class猶如設計type

這里初看到”class”和”type”&#xff0c;感覺他們是說的是同一樣東西&#xff0c;但仔細讀了一下&#xff0c;兩者在文中還是有區別的。class側重于自定義的類&#xff0c;而type側重于系統預定義的類&#xff08;像int、double、string、vector&#xff09;。設計好的class…

【TensorFlow學習筆記:神經網絡優化(6講)】

目錄【1】NN復雜度【2】指數衰減學習率【3】激活函數優秀激活函數所具有的特點常見的激活函數對于初學者的建議【4】損失函數【5】緩解過擬合——正則化【6】參數優化器【1】SGD【2】SGDM(SGD基礎上增加了一階動量)【3】Adagrade(SGD基礎上增加了二階動量)【4】RMSProp(SGD基礎…

kotlin 構造函數_Kotlin程序| 主要構造函數示例

kotlin 構造函數主要建設者 (Primary Constructor) A Kotlin class have Primary constructor and one or more Secondary constructor. Kotlin類具有Primary構造函數和一個或多個Secondary構造函數。 In Kotlin, Primary Constructor is the Part of Class Header. 在Kotlin中…

把SQL Server 錯誤日志導出為EXCEL 并發送到指定的ftp 或者 共享盤

把SQL Server 錯誤日志導出為EXCEL 并發送到指定的ftp 或者 共享盤 /* 2005版本 和2000 版本 sql server 錯誤日志結果不同。 下面是 適用于 SQL2000的 其中加入了 自己編寫的一個ftp小程序 用來上傳 相關日志狀況*/IF object_id(tempdb..#error_log) IS NOT NULLD…

c語言軟件幻化,python字符串處理

字符串字符串&#xff1a;不可變有序序列&#xff0c;在python可使用 "abc" , """abc""" ,abc 的形式表示&#xff0c;屬于一種字面常量&#xff0c;python3中字符均屬于Unicode編碼。字符串可以被迭代&#xff0c;遍歷&#xff0c;切…

第十章 開箱即用

第十章 開箱即用 “開箱即用”&#xff08;batteries included&#xff09;最初是由Frank Stajano提出的&#xff0c;指的是Python豐富的標準庫。 模塊 使用import將函數從外部模塊導入到程序中。 import math math.sin(0)#結果為&#xff1a;0.0模塊就是程序 在文件夾中創…

博客換膚

一直以來覺得博客園里的主題不是特別好&#xff0c;很多模版多多少少都有些美中不足&#xff0c;于是今天抽了點時間把主題改改&#xff0c;哈。幸虧博客園支持自定義樣式。 時間有限就先改到這里&#xff0c;今后有時間在進一步完美&#xff0c;呵呵。轉載于:https://www.cnbl…

duration java_Java Duration類| 帶示例的get()方法

duration java持續時間類get()方法 (Duration Class get() method) get() method is available in java.time package. get()方法在java.time包中可用。 get() method is used to return the value for the given unit. get()方法用于返回給定單位的值。 get() method is a non…

Openmv通過串口接收數據、發送數據與stm32通信

博主聯系方式: QQ:1540984562 QQ交流群:892023501 群里會有往屆的smarters和電賽選手,群里也會不時分享一些有用的資料,有問題可以在群里多問問。 目錄 參考接線星瞳教程openmv傳送數據STM32解碼程序參考 接線 星瞳教程