摘要:在前面介紹語法的過程中,我們已經接觸到了解釋器給的錯誤和異常,但并沒有詳細講解它們。解釋器這樣報出的好處是告訴我們哪一行代碼出錯了錯誤的類型是什么。
在前面介紹Python語法的過程中,我們已經接觸到了解釋器給的錯誤和異常,但并沒有詳細講解它們。現在我們就全面的來學習Python是對語法錯誤等錯誤進行定義和處理的,這包括至少有兩種可以區分的錯誤,它們是語法錯誤和異常。
語法錯誤Python的語法錯誤就是不符合Python語法的錯誤,又稱為解析錯誤。這種錯誤是初學Python對語法不是很熟悉時經常犯的。比如下面的例子:
In [1]: if 2 == 3 print("imposible") File "", line 1 if 2 == 3 print("imposible") ^ SyntaxError: invalid syntax
解釋器在解釋上面的代碼時,就會發現表達式2 == 3后面少了一個冒號:,這時它就會報出一個錯誤SyntaxError: invalid syntax,并且輸出出現語法錯誤的那一行,并顯示一個“箭頭”,指向這行里面檢測到第一個錯誤。 錯誤是由箭頭指示的位置上面的 token 引起的(或者至少是在這里被檢測出的)。文件名和行號也會被輸出,以便輸入來自腳本文件時你能知道去哪檢查。
解釋器這樣報出的好處是:
(1)告訴我們哪一行代碼出錯了;
(2)錯誤的類型是什么。
這樣非常有利于我們排除錯誤,修正程序。
異常(Exception)如果我們對語法很熟悉,寫出來的代碼在語法上都是正確的,但也不能保證在執行時程序不會引發錯誤。在執行時檢測到的錯誤被稱為異常,異常不一定會導致嚴重后果,但我們不在代碼中對它們進行處理,就可能會導致程序中斷執行。下面是一些常見的錯誤異常信息:
In [2]: 5 / 0 ---------------------------- ZeroDivisionError Traceback (most recent call last)in ----> 1 5 / 0 ZeroDivisionError: division by zero In [3]: a + 3 ------------------------------ NameError Traceback (most recent call last) in ----> 1 a + 3 NameError: name "a" is not defined In [4]: 10 + "1" -------------------------------- TypeError Traceback (most recent call last) in ----> 1 10 + "1" TypeError: unsupported operand type(s) for +: "int" and "str"
我們看到,異常有不同的類型,其類型名稱會作為錯誤信息的一部分中打印出來,上述示例中的異常類型分別是:ZeroDivisionError,NameError和TypeError。對于所有內置異常,打印出來的字符串是內置異常的名稱。對于用戶定義的異常則不一定如此,但我們自定義異常時最好按照內置異常那樣去定義,這是一個很有用的規范。標準的異常類型是內置的標識符,而不是保留關鍵字。
打印出來的異常名稱后面是異常發生的原因。錯誤信息的前一部分以堆?;厮莸男问斤@示發生異常時代碼的上下文。一般它包含列出源代碼行的堆棧回溯;但是它不會顯示從標準輸入中讀取的行。
Python內置了很多異常,它們都從BaseException繼承而來,下面是內置異常的繼承關系:
異常處理既然程序會拋出異常,那我們就可以編寫代碼處理這些異常。先看下面的例子,它會讓用戶一直輸入,直到輸入的是一個有效的整數。我們也可以使用Control-C來中斷程序;這個Control-C引起的中斷會引發 KeyboardInterrupt 異常。
In [6]: while 1: ...: try: ...: n = int(input("input a number:")) ...: print("You typed number:", n) ...: break ...: except ValueError: ...: print("Nooo! It is not a number, Try agin") ...: input a number:a Nooo! It is not a number, Try agin input a number:b Nooo! It is not a number, Try agin input a number:3 You typed number: 3
當我們輸入a時,它不能轉換成整數就會報錯異常ValueError。轉換為整數的那條語句報出了異常,它后面的語句就不再執行,而是跳到except那里去執行它里面的語句。
try語句的工作原理如下:
首先,執行try 子句,即try和except關鍵詞之間的(一行或多行)語句;
如果沒有發生異常,則跳過except子句并完成try子句的執行;
如果執行try子句是發生了異常,則跳過該子句的剩下部分。然后,去匹配異常的類型和except關鍵字后面的異常,如果異常類型匹配則執行except子句,之后繼續執行try語句后面的代碼。
如果發生的異常和except后面的異常不匹配,則將其傳遞到外部的try語句,如果沒有找到處理代碼,則它是一個未處理異常,執行將停止并顯示錯誤信息。
一個try語句可以有多個except子句,以便不同的異常用不同的處理程序進行處理。每次遇到異常最多會執行一個except子句,也就是說,處理程序只處理相應的異常,而不處理同一try語句內其它處理程序的異常。但是,一個except子句可以將多個異常包含在一個元組內,例如:
try: ... except (RuntimeError, TypeError, NameError): pass
異常都是繼承于BaseException,如果except子句中的類和發生的異常是同一個類,或者是異常的基類(父類),則異常和except子句中的類是兼容的。但是,反過來則不成立。我們看看下面的代碼,它將一次打印B,C,D。
class B(Exception): pass class C(B): pass class D(C): pass for cls in [B, C, D]: try: raise cls() except D: print("D") except C: print("C") except B: print("B")
如果我把 except 子句顛倒過來,把 except B 放到第一個,猜猜它將會打印出什么?答案是它將打印 B,B,B。也就是第一個匹配的 except 子句被觸發,因為B是C、D的父類。
最后的 except 子句可以省略異常名稱,以用作通配符匹配所有的異常。這個要小心使用,因為這種方式很容易掩蓋真正的編程錯誤!但是它可用于打印錯誤消息,然后重新引發異常(同樣允許調用者處理異常):
import sys try: f = open("zzz.txt") s = f.readline() i = int(s.strip()) except OSError as err: print("OS error: {0}".format(err)) except ValueError: print("Could not convert string to integer.") except: print("Unexpected error:", sys.exc_info()[0]) raise
try 語句有一個可選的 else 子句,在使用時它必須放在所有的 except 子句后面。對于在try 子句不引發異常時必須執行的代碼來說很有用。例如:
try: f = open("zzz.txt", "r") except OSError: print("cannot open", "zzz.txt") else: print("zzz.txt", "has", len(f.readlines()), "lines") f.close()
使用else子句的好處是,它避免了意外捕獲由else子句引發的異常。也就是說,程序中我們只想捕獲open引發的異常,而不捕獲f.readlines()引發的錯誤。
異常在拋出時可能具有關聯的值,稱為異常參數。參數的存在和類型取決于異常類型。
except子句可以在異常名稱后面指定一個變量,這個變量就是該異常的實例,它的參數存儲在instance.args中。為了方便起見,異常實例定義了__str__(),因此可以直接打印參數而無需引用.args。也可以在拋出之前首先實例化異常,并根據需要向其添加任何屬性。:
In [7]: try: ...: raise Exception("認真學", "Python") ...: except Exception as e: ...: print(type(e)) ...: print(e.args) ...: print(e) ...: a, b = e.args ...: print("a =", a) ...: print("b =", b) ...:("認真學", "Python") ("認真學", "Python") a = 認真學 b = Python
異常處理程序不僅可以處理try子句中遇到的異常,還可以處理try子句中調用的函數的內部發生的異常,例如:
In [8]: def func(): ...: return 10/0 ...: In [9]: try: ...: func() ...: except ZeroDivisionError as err: ...: print("run-time error:", err) ...: run-time error: division by zero
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/43850.html
摘要:語句就是幫助我們拋出知道異常的,比如的使用很簡單,它的語法如下如果它后面不帶表達式參數,它會重新引發當前作用域內最后一個激活的異常。,用于異常的串聯。自定義的異常類的名稱通常以錯誤結尾,類似與內置標準異常的命名。 前面我們講到的Python編程過程中,在可能出現異常的地方使用嘗試語句,來正確的處理一些異常,可以保證程序不中斷繼續運行。 showImg(https://segmentfa...
摘要:新的稱為子類,而被繼承的稱為基類父類或超類。繼承最大的好處是子類獲得了父類的全部功能。在繼承關系中,如果一個實例的數據類型是某個子類,那它的數據類型也可以被看做是父類。 在上一篇中我們介紹了模塊和數據結構,這一篇將介紹面向對象編程。 面向對象編程 面向對象編程——Object Oriented Programming,簡稱 OOP,是一種程序設計思想。OOP 把對象作為程序的基本單元...
?前言 代碼出現異常而報錯再正常不過了,但為什么要處理異常? 由于異常的存在,代碼運行時會出現一大堆的紅色字體提示,對于程序員還好,見紅色報錯見多了習慣了,但如果你開發出來的東西要給別人看,那么不懂代碼的人就會一臉懵逼,對產品的印象都不太好了。 比如我們經常簡單網頁丟失的情況,其實是就是網頁代碼執行時發生了異常,但有的網頁還是很個性的,提示的信息可能是比較人性化的,比如CSDN你收藏的文章被后臺刪...
摘要:本文與大家分享一些編程語言的入門書籍,其中不乏經典。全書貫穿的主體是如何思考設計開發的方法,而具體的編程語言,只是提供一個具體場景方便介紹的媒介。入門入門容易理解而且讀起來幽默風趣,對于編程初學者和語言新手而言是理想的書籍。 本文與大家分享一些Python編程語言的入門書籍,其中不乏經典。我在這里分享的,大部分是這些書的英文版,如果有中文版的我也加上了。有關書籍的介紹,大部分截取自是官...
閱讀 3371·2023-04-25 14:07
閱讀 3437·2021-09-28 09:35
閱讀 2079·2019-08-30 15:55
閱讀 1396·2019-08-30 13:48
閱讀 2496·2019-08-30 13:16
閱讀 3196·2019-08-30 12:54
閱讀 3231·2019-08-30 11:19
閱讀 1868·2019-08-29 17:17