鍍金池/ 教程/ Python/ 錯誤和異常 (1)
標準庫 (4)
如何成為 Python 高手
標準庫 (6)
標準庫 (3)
類(2)
Pandas 使用 (2)
xml
用 tornado 做網站 (5)
文件(1)
練習
列表(3)
從小工到專家
除法
錯誤和異常 (2)
函數(1)
用 tornado 做網站 (7)
為做網站而準備
函數練習
標準庫 (8)
Pandas 使用 (1)
回顧 list 和 str
字典(1)
用 tornado 做網站 (3)
字符串(1)
函數(2)
寫一個簡單的程序
將數據存入文件
語句(5)
SQLite 數據庫
集成開發(fā)環(huán)境(IDE)
集合(1)
類(1)
用 tornado 做網站 (6)
用 tornado 做網站 (2)
自省
語句(4)
錯誤和異常 (1)
用 tornado 做網站 (4)
集合(2)
列表(1)
標準庫 (1)
生成器
mysql 數據庫 (1)
第三方庫
實戰(zhàn)
運算符
類(3)
字典(2)
語句(1)
數和四則運算
語句(2)
文件(2)
MySQL 數據庫 (2)
電子表格
迭代器
mongodb 數據庫 (1)
特殊方法 (2)
特殊方法 (1)
字符編碼
編寫模塊
用 tornado 做網站 (1)
標準庫 (5)
函數(4)
類(5)
字符串(2)
關于 Python 的故事
函數(3)
字符串(4)
處理股票數據
常用數學函數和運算優(yōu)先級
字符串(3)
為計算做準備
多態(tài)和封裝
類(4)
迭代
語句(3)
錯誤和異常 (3)
分析 Hello
Python 安裝
標準庫 (2)
列表(2)
元組

錯誤和異常 (1)

錯誤和異常 (1)

雖然在前面的學習中,已經遇到了錯誤和異常問題,但是一直沒有很認真的研究它?,F在來近距離觀察錯誤和異常。

錯誤

Python 中的錯誤之一是語法錯誤(syntax errors),比如:

>>> for i in range(10)
  File "<stdin>", line 1
    for i in range(10)
                     ^
SyntaxError: invalid syntax

上面那句話因為缺少冒號:,導致解釋器無法解釋,于是報錯。這個報錯行為是由 Python 的語法分析器完成的,并且檢測到了錯誤所在文件和行號(File "<stdin>", line 1),還以向上箭頭^標識錯誤位置(后面缺少:),最后顯示錯誤類型。

錯誤之二是在沒有語法錯誤之后,會出現邏輯錯誤。邏輯錯誤可能會由于不完整或者不合法的輸入導致,也可能是無法生成、計算等,或者是其它邏輯問題。

當 Python 檢測到一個錯誤時,解釋器就無法繼續(xù)執(zhí)行下去,于是拋出異常。

異常

看一個異常(讓 0 做分母了,這是小學生都相信會有異常的):

>>> 1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

當 Python 拋出異常的時候,首先有“跟蹤記錄(Traceback)”,還可以給它取一個更優(yōu)雅的名字“回溯”。后面顯示異常的詳細信息。異常所在位置(文件、行、在某個模塊)。

最后一行是錯誤類型以及導致異常的原因。

下表中列出常見的異常

異常 描述
NameError 嘗試訪問一個沒有申明的變量
ZeroDivisionError 除數為 0
SyntaxError 語法錯誤
IndexError 索引超出序列范圍
KeyError 請求一個不存在的字典關鍵字
IOError 輸入輸出錯誤(比如你要讀的文件不存在)
AttributeError 嘗試訪問未知的對象屬性

為了能夠深入理解,依次舉例,展示異常的出現條件和結果。

NameError

>>> bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'bar' is not defined

Python 中變量需要初始化,即要賦值。雖然不需要像某些語言那樣聲明,但是要賦值先。因為變量相當于一個標簽,要把它貼到對象上才有意義。

ZeroDivisionError

>>> 1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

貌似這樣簡單的錯誤時不會出現的,但在實際情境中,可能沒有這么容易識別,所以,依然要小心為妙。

SyntaxError

>>> for i in range(10)
  File "<stdin>", line 1
    for i in range(10)
                     ^
SyntaxError: invalid syntax

這種錯誤發(fā)生在 Python 代碼編譯的時候,當編譯到這一句時,解釋器不能講代碼轉化為 Python 字節(jié)碼,就報錯。只有改正才能繼續(xù)。所以,它是在程序運行之前就會出現的(如果有錯)?,F在有不少編輯器都有語法校驗功能,在你寫代碼的時候就能顯示出語法的正誤,這多少會對編程者有幫助。

IndexError

>>> a = [1,2,3]
>>> a[4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

>>> d = {"python":"itdiffer.com"}
>>> d["java"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'java'

這兩個都屬于“雞蛋里面挑骨頭”類型,一定得報錯了。不過在編程實踐中,特別是循環(huán)的時候,常常由于循環(huán)條件設置不合理出現這種類型的錯誤。

IOError

>>> f = open("foo")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'foo'

如果你確認有文件,就一定要把路徑寫正確,因為你并沒有告訴 Python 對你的 computer 進行全身搜索,所以,Python 會按照你指定位置去找,找不到就異常。

AttributeError

>>> class A(object): pass
... 
>>> a = A()
>>> a.foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'foo'

屬性不存在。這種錯誤前面多次見到。

其實,Python 內建的異常也不僅僅上面幾個,上面只是列出常見的異常中的幾個。比如還有:

>>> range("aaa")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: range() integer end argument expected, got str.

總之,如果讀者在調試程序的時候遇到了異常,不要慌張,這是好事情,是 Python 在幫助你修改錯誤。只要認真閱讀異常信息,再用 dir(),help() 或者官方網站文檔、google 等來協(xié)助,一定能解決問題。

處理異常

在一段程序中,為了能夠讓程序健壯,必須要處理異常。舉例:

#!/usr/bin/env Python
# coding=utf-8

while 1:
    print "this is a division program."
    c = raw_input("input 'c' continue, otherwise logout:")
    if c == 'c':
        a = raw_input("first number:")
        b = raw_input("second number:")
        try:
            print float(a)/float(b)
            print "*************************"
        except ZeroDivisionError:
            print "The second number can't be zero!"
            print "*************************"
    else:
        break

運行這段程序,顯示如下過程:

$ python 21601.py 
this is a division program.
input 'c' continue, otherwise logout:c
first number:5
second number:2
2.5
*************************
this is a division program.
input 'c' continue, otherwise logout:c
first number:5
second number:0
The second number can't be zero!
*************************
this is a division program.
input 'c' continue, otherwise logout:d
$

從運行情況看,當在第二個數,即除數為 0 時,程序并沒有因為這個錯誤而停止,而是給用戶一個友好的提示,讓用戶有機會改正錯誤。這完全得益于程序中“處理異?!钡脑O置,如果沒有“處理異?!?,異常出現,就會導致程序終止。

處理異常的方式之一,使用 try...except...。

對于上述程序,只看 try 和 except 部分,如果沒有異常發(fā)生,except 子句在 try 語句執(zhí)行之后被忽略;如果 try 子句中有異???,該部分的其它語句被忽略,直接跳到 except 部分,執(zhí)行其后面指定的異常類型及其子句。

except 后面也可以沒有任何異常類型,即無異常參數。如果這樣,不論 try 部分發(fā)生什么異常,都會執(zhí)行 except。

在 except 子句中,可以根據異?;蛘邉e的需要,進行更多的操作。比如:

#!/usr/bin/env Python
# coding=utf-8

class Calculator(object):
    is_raise = False
    def calc(self, express):
        try:
            return eval(express)
        except ZeroDivisionError:
            if self.is_raise:
                print "zero can not be division."
            else:
                raise

在這里,應用了一個函數 eval(),它的含義是:

eval(...)
    eval(source[, globals[, locals]]) -> value

    Evaluate the source in the context of globals and locals.
    The source may be a string representing a Python expression
    or a code object as returned by compile().
    The globals must be a dictionary and locals can be any mapping,
    defaulting to the current globals and locals.
    If only globals is given, locals defaults to it.

例如:

>>> eval("3+5")
8

另外,在 except 子句中,有一個 raise,作為單獨一個語句。它的含義是將異常信息拋出。并且,except 子句用了一個判斷語句,根據不同的情況確定走不同分支。

if __name__ == "__main__":
    c = Calculator()
    print c.calc("8/0")

這時候 is_raise = False,則會:

$ python 21602.py 
Traceback (most recent call last):
  File "21602.py", line 17, in <module>
    print c.calc("8/0")
  File "21602.py", line 8, in calc
    return eval(express)
  File "<string>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

如果將 is_raise 的值改為 True,就是這樣了:

if __name__ == "__main__":
    c = Calculator()
    c.is_raise = True    #通過實例屬性修改
    print c.calc("8/0")

運行結果:

$ python 21602.py 
zero can not be division.
None

最后的 None 是 c.calc("8/0")的返回值,因為有 print c.calc("8/0"),所以被打印出來。


總目錄   |   上節(jié):生成器   |   下節(jié):錯誤和異常(2)

如果你認為有必要打賞我,請通過支付寶:qiwsir@126.com,不勝感激。

上一篇:標準庫 (8)下一篇:迭代