在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ 錯誤和異常
浮點運算
非正式的 Python 簡介
深入流程控制
標準庫概覽
交互式輸入行編輯歷史回溯
輸入和輸出
使用 Python 解釋器
標準庫概覽Ⅱ
錯誤和異常
模塊
數據結構
附錄
接下來?
激起你的興趣

錯誤和異常

至今為止還沒有進一步的談論過錯誤信息,不過在你已經試驗過的那些例子中,可能已經遇到過一些。Python 中(至少)有兩種錯誤:語法錯誤和異常(?syntax errors?和?exceptions?)。

語法錯誤

語法錯誤,也被稱作解析錯誤,也許是你學習 Python 過程中最常見抱怨:

>>> while True print('Hello world')   
  File "<stdin>", line 1, in ?     
     while True print('Hello world')
                    ^
SyntaxError: invalid syntax  

語法分析器指出錯誤行,并且在檢測到錯誤的位置前面顯示一個小“箭頭”。 錯誤是由箭頭?前面?的標記引起的(或者至少是這么檢測的): 這個例子中,函數?print()?被發(fā)現存在錯誤,因為它前面少了一個冒號(':'?)。 錯誤會輸出文件名和行號,所以如果是從腳本輸入的你就知道去哪里檢查錯誤了。

異常

即使一條語句或表達式在語法上是正確的,當試圖執(zhí)行它時也可能會引發(fā)錯誤。 運行期檢測到的錯誤稱為異常?,并且程序不會無條件的崩潰:很快,你將學到如何在 Python 程序中處理它們。 然而,大多數異常都不會被程序處理,像這里展示的一樣最終會產生一個錯誤信息:

>>> 10 * (1/0)  
Traceback (most recent call last):  
  File "<stdin>", line 1, in ?    
ZeroDivisionError: division by zero    
>>> 4 + spam*3  
Traceback (most recent call last):   
  File "<stdin>", line 1, in ?  
NameError: name 'spam' is not defined  
>>> '2' + 2  
Traceback (most recent call last):  
  File "<stdin>", line 1, in ?  
TypeError: Can't convert 'int' object to str implicitly

錯誤信息的最后一行指出發(fā)生了什么錯誤。異常也有不同的類型,異常類型做為錯誤信息的一部分顯示出來:示例中的異常分別為零除錯誤(ZeroDivisionError?) ,命名錯誤(?NameError)和 類型錯誤(?TypeError)。打印錯誤信息時,異常的類型作為異常的內置名顯示。對于所有的內置異常都是如此,不過用戶自定義異常就不一定了(盡管這是一個很有用的約定)。標準異常名是內置的標識(沒有保留關鍵字)。

這一行后一部分是關于該異常類型的詳細說明,這意味著它的內容依賴于異常類型。

錯誤信息的前半部分以堆棧的形式列出異常發(fā)生的位置。通常在堆棧中列出了源代碼行,然而,來自標準輸入的源碼不會顯示出來。

bltin-exceptions?列出了內置異常和它們的含義。

控制異常

可以編寫程序來控制已知的異常。參見下例,此示例要求用戶輸入信息,一直到 得到一個有效的整數為止,而且允許用戶中斷程序(使用 Control-C 或 其它什么操作系統(tǒng)支持的操作);需要注意的是用戶生成的中斷會拋出 KeyboardInterrupt 異常

>>> while True:  
...     try:  
...         X = int(input("Please enter a number: "))  
...         break   
...     except ValueError:  
...         print("Oops!  That was no valid number.  Try again...")  
...

try?語句按如下方式工作。

  • 首先,執(zhí)行?try?子句 (在?try?和?except?關鍵字之間的部分)。
  • 如果沒有異常發(fā)生,?except?子句 在?try?語句執(zhí)行完畢后就被忽略了。
  • 如果在 try 子句執(zhí)行過程中發(fā)生了異常,那么該子句其余的部分就會被忽略。如果異常匹配于?except?關鍵字后面指定的異常類型,就執(zhí)行對應的except 子句。然后繼續(xù)執(zhí)行?try?語句之后的代碼。
  • 如果發(fā)生了一個異常,在?except?子句中沒有與之匹配的分支,它就會傳遞到上一級?try?語句中。如果最終仍找不到對應的處理語句,它就成為一個?未處理異常?,終止程序運行,顯示提示信息。

一個?try?語句可能包含多個 except 子句,分別指定處理不同的異常。至多只會有一個分支被執(zhí)行。異常處理程序只會處理對應的 try 子句中發(fā)生的異常,在同一個?try?語句中,其他子句中發(fā)生的異常則不作處理。一個 except 子句可以在括號中列出多個異常的名字,例如:

... except (RuntimeError, TypeError, NameError):  
...   pass  

最后一個 except 子句可以省略異常名稱,以作為通配符使用。 你需要慎用此法,因為它會輕易隱藏一個實際的程序錯誤! 可以使用這種方法打印一條錯誤信息,然后重新拋出異常(允許調用者處理這個異常):

Import sys

try:  
    f = open('myfile.txt')  
    S = f.readline()  
    I = int(s.strip())  
except OSError as err:  
    print("OS error: {0}".format(err))  
except ValueError:  
    print("Could not convert data to an integer.")  
except:   
    print("Unexpected error:", sys.exc_info()[0])  
    raise  

try?...?except?語句可以帶有一個?else 子句?,該子句只能出現在所有 except 子句之后。當 try 語句沒有拋出異常時,需要執(zhí)行一些代碼,可以使用這個子句。例如:

For arg in sys.argv[1:]:  
try:  
    f = open(arg, 'r')  
except IOError:  
    print('cannot open', arg)  
else:  
   print(arg, 'has', len(f.readlines()), 'lines')  
   f.close()  

使用?else?子句比在?try?子句中附加代碼要好,因為這樣可以避免?try...?except?意外的截獲本來不屬于它們保護的那些代碼拋出的異常。

發(fā)生異常時,可能會有一個附屬值,作為異常的參數?存在。這個參數是否存在、是什么類型,依賴于異常的類型。

在異常名(列表)之后,也可以為 except 子句指定一個變量。這個變量綁定于一個異常實例,它存儲在?instance.args?的參數中。為了方便起見,異常實例定義了?__str__()?,這樣就可以直接訪問過打印參數而不必引用?.args。 這種做法不受鼓勵。相反,更好的做法是給異常傳遞一個參數(如果要傳遞多個參數,可以傳遞一個元組),把它綁定到 message 屬性。一旦異常發(fā)生,它會在拋出前綁定所有指定的屬性。

>>> try:  
...     Raise Exception('spam', 'eggs')  
... except Exception as inst:  
...    print(type(inst))     # the exception instance    
...    print(inst.args)      # arguments stored in .args    
...    print(inst)           # __str__ allows args to be     printed directly,  
...                          # but may be overridden in exception subclasses  
...    x, y = inst.args      # unpack args  
...    print('x =', x)  
...    print('y =', y)  
...  
<class 'Exception'>  
('spam', 'eggs')  
('spam', 'eggs')  
x = spam
y = eggs

對于那些未處理的異常,如果一個它們帶有參數,那么就會被作為異常信息的最后部分(“詳情”)打印出來。

異常處理器不僅僅處理那些在 try 子句中立刻發(fā)生的異常,也會處理那些 try 子句中調用的函數內部發(fā)生的異常。 例如:

>>> def this_fails():  
...     X = 1/0  
...
>>> try:  
...     this_fails()  
... except ZeroDivisionError as err:  
...     print('Handling run-time error:', err)  
...  
Handling run-time error: int division or modulo by zero  

拋出異常

raise?語句允許程序員強制拋出一個指定的異常。例如:

>>> raise NameError('HiThere')    
Traceback (most recent call last):    
  File "<stdin>", line 1, in ?  
NameError: HiThere  

要拋出的異常由?raise?的唯一參數標識。它必需是一個異常實例或異常類(繼承自?Exception?的類)。

如果你需要明確一個異常是否拋出,但不想處理它,?raise?語句可以讓你很簡單的重新拋出該異常:

>>> try:  
...      raise NameError('HiThere')  
... except NameError:  
...     print('An exception flew by!')  
...     Raise  
...  
An exception flew by!  
Traceback (most recent call last):   
  File "<stdin>", line 2, in ?  
NameError: HiThere  

用戶自定義異常

在程序中可以通過創(chuàng)建新的異常類型來命名自己的異常(Python 類的內容請參見?類?)。異常類通常應該直接或間接的從?Exception?類派生,例如:

>>> class MyError(Exception):  
...     def __init__(self, value):  
...        self.value = value  
...     def __str__(self):  
...       return repr(self.value)  
...
>>> try:  
...      raise MyError(2*2)  
...   except MyError as e:  
...      print('My exception occurred, value:', e.value)  
...  
My exception occurred, value: 4  
>>> raise MyError('oops!')    
Traceback (most recent call last):   
  File "<stdin>", line 1, in ?  
__main__.MyError: 'oops!'  

在這個例子中,Exception?默認的?__init__()?被覆蓋。新的方式簡單的創(chuàng)建?value?屬性。這就替換了原來創(chuàng)建?args?屬性的方式。

異常類中可以定義任何其它類中可以定義的東西,但是通常為了保持簡單,只在其中加入幾個屬性信息,以供異常處理句柄提取。如果一個新創(chuàng)建的模塊中需要拋出幾種不同的錯誤時,一個通常的作法是為該模塊定義一個異?;?,然后針對不同的錯誤類型派生出對應的異常子類:

class Error(Exception):   
    """Base class for exceptions in this module."""  
    pass  
class InputError(Error):  
    """Exception raised for errors in the input.

    Attributes:          
         expression -- input expression in which the error occurred
         message -- explanation of the error      
     """ 

     def __init__(self, expression, message):  
         self.expression = expression  
         self.message = message

class TransitionError(Error):  
    """Raised when an operation attempts a state transition that's not
    allowed.

    Attributes:      
        previous -- state at beginning of transition      
        next -- attempted new state        
        message -- explanation of why the specific transition is not allowed    
     """   
     def __init__(self, previous, next, message):  
         self.previous = previous  
         self.next = next  
         self.message = message  

與標準異常相似,大多數異常的命名都以 “Error” 結尾。

很多標準模塊中都定義了自己的異常,用以報告在他們所定義的函數中可能發(fā)生的錯誤。關于類的進一步信息請參見

定義清理行為

try?語句還有另一個可選的子句,目的在于定義在任何情況下都一定要執(zhí)行的功能。例如:

>>> try:   
...      raise KeyboardInterrupt  
... finally:  
...     print('Goodbye, world!')  
...  
Goodbye, world!  
KeyboardInterrupt  

不管有沒有發(fā)生異常,?finally 子句?在程序離開?try?后都一定會被執(zhí)行。當?try?語句中發(fā)生了未被?except?捕獲的異常(或者它發(fā)生在except?或?else?子句中),在?finally?子句執(zhí)行完后它會被重新拋出。try?語句經由?break?,continue?或?return?語句退 出也一樣會執(zhí)行finally?子句。以下是一個更復雜些的例子

>>> def divide(x, y):  
...     try:  
...       result = x / y  
...    except  ZeroDivisionError:  
...        print("division by zero!")  
...    else:  
...        print("result is", result)   
...    finally:   
...        print("executing finally clause")   
...  
>>> divide(2, 1)  
result is 2.0  
executing finally clause  
>>> divide(2, 0)  
division by zero!    
executing finally clause     
>>> divide("2", "1")    
executing finally clause    
Traceback (most recent call last):    
  File "<stdin>", line 1, in ?    
  File "<stdin>", line 3, in divide  
TypeError: unsupported operand type(s) for /: 'str' and 'str'

如你所見,?finally?子句在任何情況下都會執(zhí) 行。?TypeError?在兩個字符串相除的時候拋出,未被 except 子句捕獲,因此在?finally?子句執(zhí)行完畢后重新拋出。

在真實場景的應用程序中,?finally?子句用于釋放外部資源(文件 或網絡連接之類的),無論它們的使用過程中是否出錯。

預定義清理行為

有些對象定義了標準的清理行為,無論對象操作是否成功,不再需要該對象的時 候就會起作用。以下示例嘗試打開文件并把內容打印到屏幕上。

for line in open("myfile.txt"):  
    print(line, end="")  

這段代碼的問題在于在代碼執(zhí)行完后沒有立即關閉打開的文件。這在簡單的腳本 里沒什么,但是大型應用程序就會出問題。?with?語句使得文件之類的對象可以 確??偰芗皶r準確地進行清理。

with open("myfile.txt") as f:  
   for line in f:  
       print(line, end="")  

語句執(zhí)行后,文件?f?總會被關閉,即使是在處理文件中的數據時出錯也一樣。 其它對象是否提供了預定義的清理行為要查看它們的文檔。

上一篇:附錄下一篇:深入流程控制