天天看點

《Beginning Python From Novice to Professional》學習筆記十:Exception

0.最重要的内置異常

Exception:所有異常的基類

AttributeError:屬性引用或指派異常

IOError:試圖讀、寫不存在的檔案

IndexError:使用Sequence中不存在的Index

KeyError:使用Mapping中不存在的Key

NameError:變量名未找到

SyntaxError:文法錯

TypeError:在内置函數中使用錯誤的類型

ValueError:類型對,但值不正确

ZeroDivisionError:除零

1.自定義異常

class SomeCustomException(Exception): pass

2.捕獲異常

try:

x = input('Enter the first number: ')

y = input('Enter the second number: ')

print x/y

except ZeroDivisionError:

print "The second number can't be zero!"

   #适合于人機互動

3.無參數raise重新抛出異常reraises

class MuffledCalculator:

muffled = 0

def calc(self, expr):

try:

return eval(expr)

except ZeroDivisionError:

if self.muffled:

print 'Division by zero is illegal'

else:

raise

   #适合于程式間互動

#注意在除以零且muffled不為零的情況下,程式的傳回值為None

4.多Exception分支

try:

x = input('Enter the first number: ')

y = 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?"

5.在一句中同時捕獲多個Exception

try:

x = input('Enter the first number: ')

y = input('Enter the second number: ')

print x/y

except (ZeroDivisionError, TypeError): #前後的括号實際上起到了組裝成Tuple的作用

print 'Your numbers were bogus...'

6.同時捕獲多個,而且能甄别具體是哪個

try:

x = input('Enter the first number: ')

y = input('Enter the second number: ')

print x/y

except (ZeroDivisionError, TypeError), e: #e指代實際被捕獲的那個

print e

7.捕獲一切異常

try:

x = input('Enter the first number: ')

y = input('Enter the second number: ')

print x/y

except:

print 'Something wrong happened...'

但這種捕獲方式比較危險,因為它會忽略程式中你未曾想到的錯誤,同時也不能針對錯誤來處理,是以盡量采用以下形式來捕獲所有異常:

try:

x = input('Enter the first number: ')

y = input('Enter the second number: ')

print x/y

except Exception, e:

print e #Or do something about e

8.When All Is Well

不知咋翻,多用于輸入時,不斷提示輸入直到一切就緒

while 1:

try:

x = input('Enter the first number: ')

y = input('Enter the second number: ')

value = x/y

print 'x/y is', value

except Exception, e:

print 'Invalid input:', e

print 'Please try again'

else:

break

9.finally

在出現可能的異常之後做一些清理工作

x = None #初始化x是因為否則 del x 會引發異常

try:

x = 1/0

finally:

print 'Cleaning up...'

del x

結果為:--->

Cleaning up...

Traceback (most recent call last):

  File "C:/python/div.py", line 4, in ?

    x = 1/0

ZeroDivisionError: integer division or modulo by zero

也可以加上except:

x = None

try:

x = 1/0

except Exception, e:

print e

finally:

print 'Cleaning up...'

del x

結果為: --->

integer division or modulo by zero

Cleaning up...

10.異常跟蹤

如果一個異常在函數A内部被引發,但沒有被處理,它将被傳遞給調用它的函數B,如果在B處又未處理,它将繼續上溯傳遞,直到全局域内的函數G,如果在G中仍未被處理,整個程式将halt并顯示錯誤資訊(a stack trace):

def faulty():

raise Exception('Something is wrong')

def ignore_exception():

faulty()

def handle_exception():

try:

faulty()

except:

print 'Exception handled'

ignore_exception()   --->

Traceback (most recent call last):

  File '<stdin>', line 1, in ?

  File '<stdin>', line 2, in ignore_exception

  File '<stdin>', line 2, in faulty

Exception: Something is wrong

handle_exception()   --->

Exception handled   #隻要在任何一處被處理了,則整個程式不被因為此Exception而Halt。

11.The Zen of Exceptions - Exception哲理

比較下面兩段代碼:

def describePerson(person):

print 'Description of', person['name']

print 'Age:', person['age']

if 'occupation' in person:

print 'Occupation:', person['occupation']

def describePerson(person):

print 'Description of', person['name']

print 'Age:', person['age']

try: print 'Occupation:', person['occupation']

except KeyError: pass

其中第一段會查找Key “occupation”兩次,一次判斷,一次取值;而第二段代碼則隻要一次。

但在大多數情況下,用try/exception還是if/else隻是個人喜好的不同(a matter of taste)。對性能的影響不大,而且程式設計時對性能的考慮是第二位的。

The point is that using a try/except statement is in many cases much more natural (more “Pythonic”) than if/else。應該盡量使用它。

最後引用Grace Hopper's words of wisdom, “It’s easier to ask forgiveness than permission.”

這種政策叫Leap Before You Look idiom.