拋出異常
#coding=utf-8
def exceptionTest(num):
if num<0:
print "if num<0"
raise Exception("Invalid num")
else:
print num
if num == 0:
raise ZeroDivisionError("interger division or modulo by zero")
print exceptionTest(-43)
c:\Python27\Scripts>python task_test.py
if num<0
Traceback (most recent call last):
File "task_test.py", line 14, in <module>
print exceptionTest(-43)
File "task_test.py", line 7, in exceptionTest
raise Exception("Invalid num")
Exception: Invalid num
#coding=utf-8
def exceptionTest(num):
if num<0:
print "if num<0"
raise Exception("Invalid num")
else:
print num
if num == 0:
raise ZeroDivisionError("interger division or modulo by zero")
return ""
print exceptionTest(4)
c:\Python27\Scripts>python task_test.py
4
#coding=utf-8
def exceptionTest(num):
if num<0:
print "if num<0"
raise Exception("Invalid num")
else:
print num
if num == 0:
raise ZeroDivisionError("interger division or modulo by zero")
return ""
print exceptionTest(0)
c:\Python27\Scripts>python task_test.py
0
Traceback (most recent call last):
File "task_test.py", line 14, in <module>
print exceptionTest(0)
File "task_test.py", line 11, in exceptionTest
raise ZeroDivisionError("interger division or modulo by zero")
ZeroDivisionError: interger division or modulo by zero
自定義異常
通過創建一個新的異常類,程序可以創建它們自己特定的異常。自定義異常都需要繼承異常基類(Exception類),當然也可以繼承具體的異常類(比如RuntimeError),通過直接或間接的方式。
#coding=utf-8
class Neterror(RuntimeError):
def __init__(self,value):#重寫默認的__ini__()方法
self.value=value
#觸發自定義的異常
try:
raise Neterror("Bad hostname")
except Neterror,e:
print "My exception occurred,value:",e.value
c:\Python27\Scripts>python task_test.py
My exception occurred,value: Bad hostna
#coding=utf-8
class ShortInputException(Exception):
''' A user-defined exception class.'''
def __init__(self,length,atleast):
Exception.__init__(self)
self.length = length
self.atleast = atleast
try:
s= raw_input('Enter something-->')
if len(s)<3:
#如果輸入的內容長度小於3,觸發異常
raise ShortInputException(len(s),3)
except EOFError:
print '\nWhy did you do an EOF on me?'
except ShortInputException,x:
print "shortInputException:The input was of length %d,\
was excepting at least %d"%(x.length,x.atleast)
else:
print "No exception was raised"
c:\Python27\Scripts>python task_test.py
Enter something-->234s
No exception was raised
c:\Python27\Scripts>python task_test.py
Enter something-->3e3
No exception was raised
c:\Python27\Scripts>python task_test.py
Enter something-->w
shortInputException:The input was of length 1, was excepting at least 3
c:\Python27\Scripts>python task_test.py
Enter something-->
shortInputException:The input was of length 0, was excepting at least 3
異常拋出機制:
1、如果在運行時發生異常,解釋器會查找相應的處理語句(稱為handler)。
2、要是在當前函數里沒有找到的話,它會將異常傳遞給上層的調用函數,看看 那里能不能處理。
3、如果在最外層(全局“main”)還是沒有找到的話,解釋器就會退出,同時打印出traceback以便讓用戶找到錯誤產生的原因。
注意:
雖然大多數錯誤會導致異常,但一個異常不一定代表錯誤,有時候它們只是一個警告,有時候它們可能是一個終止信號,比如退出循環等
標准異常說明
上面列舉的標准異常集,所有的異常都是內建的.。所以它們在腳本啟動前或在互交命令行提示符出現時已經是可用的了。
所有的標准/內建異常都是從根異常派生的。目前,有3 個直接從BaseException 派生的異常子類:SystemExit,KeyboardInterrupt 和Exception。其他的所有的內建異常都是Exception 的子類。
Python2.5開始,所有的異常的都是BaseException 的子類。
With介紹:
with是從Python2.5引入的一個新的語法,它是一種上下文管理協議,目的在於從流程圖中把 try,except 和finally 關鍵字和資源分配釋放相關
代碼統統去掉,簡化try….except….finlally的處理流程。with通過__enter__方法初始化,然后在__exit__中做善后以及處理異常。所以使用with處理的對象必須有__enter__()和__exit__()這兩個方法。其中__enter__()方法在語句體(with語句包裹起來的代碼塊)執行之前進入運行,__exit__()方法在語句體執行完畢退出后運行。
with 語句適用於對資源進行訪問的場合,確保不管使用過程中是否發生異常都會執行必要的“清理”操作,釋放資源,比如文件使用后自動關閉、線程中鎖的自動獲取和釋放等。
With語句的基本語法格式如下
with expression [as target]:
with_body
參數說明:
expression:是一個需要執行的表達式;
target:是一個變量或者元組,存儲的是expression表達式執行返回的結果, 可選參數。
#coding=utf-8
with open("d:\\a.txt",'r') as fp:
print fp.read()
c:\Python27\Scripts>python task_test.py
sdfsdfsdfsdf1
with語句的工作原理:
緊跟with后面的語句會被求值,返回對象的__enter__()方法被調用,這個方法的返回值將被賦值給as關鍵字后面的變量,當with后面的代碼塊全部被執行完之后,將調用前面返回對象的__exit__()方法。
從前面我們知道,with語句最關鍵的地方在於被求值對象必須有__enter__()和__exit__()這兩個方法,那我們就可以通過自己實現這兩方法來自定義with語句處理異常。
#coding=utf-8
class opened(object):
def __init__(self,filename):
self.handle=open(filename)
print "Resource:%s" %filename
def __enter__(self):
print "[Enter%s]:Allocate resource." %self.handle
return self.handle#可以返回不同的對象
def __exit__(self,exc_type,exc_value,exc_trackback):
print "[Exit%s]:Free resource." %self.handle
if exc_trackback is None:
print "[Exit%s]:Exited without exception." %self.handle
self.handle.close()
else:
print "[Exit %s]: Exited with exception raised." %self.handle
return False#可以省略,缺省的None也是被看作是False
with opened("d:\\a.txt") as fp:
for line in fp.readlines():
print line
c:\Python27\Scripts>python task_test.py
Resource:d:\a.txt
[Enter<open file 'd:\\a.txt', mode 'r' at 0x0000000002BC7150>]:Allocate resource.
sdfsdfsdfsdf1
[Exit<open file 'd:\\a.txt', mode 'r' at 0x0000000002BC7150>]:Free resource.
[Exit<open file 'd:\\a.txt', mode 'r' at 0x0000000002BC7150>]:Exited without exception.
示例代碼說明:
opened中的__enter__() 返回的是自身的引用,這個引用可以賦值給 as 子句中的fp變量;返回值的類型可以根據實際需要設置為不同的類型,不必是上下文管理器對象本身。
__exit__() 方法中對變量exc_trackback進行檢測,如果不為 None,表示發生了異常,返回 False 表示需要由外部代碼邏輯對異常進行處理;如果沒有發生異常,缺省的返回值為 None,在布爾環境中也是被看做 False,但是由於沒有異常發生,__exit__() 的三個參數都為 None,上下文管理代碼可以檢測這種情況,做正常處理。__exit__()方法的3個參數,分別代表異常的類型、值、以及堆棧信息。
命名空間
Random是命名空間
導入ramdom命名空間里的randint函數
#encoding=utf-8
>>> from random import randint
>>> print randint(10,20)
18
一起引入兩個
>>> from random import randint,choice
>>> print randint(10,20)
11
>>> print choice([1,2,3,4])
3
>>>
直接用*,引入所有函數,但是壞處是如果本地有一個自定義的函數與命名空間里的函數同名,命名空間里的該函數會被覆蓋
>>> from random import *
>>> print randint(10,20)
14
>>> print choice([1,2,3,4])
4
>>>
覆蓋例子:
#coding=utf-8
from random import *
def randint():
return 1
print randint(1,20)
c:\Python27\Scripts>python task_test.py
Traceback (most recent call last):
File "task_test.py", line 8, in <module>
print randint(1,20)
TypeError: randint() takes no arguments (2 given)
練習:
生成一個模塊a.py,里面定義一個變量c=100,定義一個函數def add(a,b) 在b.py中通過import a 和from a import *的兩種方法來引入使用c變量和add函數
a.py:
import b
c=100
def add(a,b):
return a+b
b.py:
import a
print a.c
print a.add(1,2)
c:\Python27\Scripts>python task_test.py
100
3
b.py:
#coding=utf-8
from a import *
print c
print add(1,2)
c:\Python27\Scripts>python task_test.py
100
3
如果一個py文件中有if __name__ == '__main__':,只有在運行該文件時才會執行,該文件在別文件中引用,不會被執行
a.py:
#encoding=utf-8
c=100
def add(a,b):
return a+b
if __name__=='__main__':
print c
print add(10,20)
c:\Python27\Scripts>python a.py
100
30
b.py:
#coding=utf-8
from a import *
print c+add(1,2)
c:\Python27\Scripts>python task_test.py
103
沒有顯示a.py中if __name__==’__main__’:下邊的代碼
在b.py中import a, 則a.py中的代碼會都執行一遍
import a
reload(a)
reload后會再執行一遍a中的代碼
如果import a兩次,則只執行一遍a中的代碼
Import a
Import a
a.py:
#encoding=utf-8
c=100
def add(a,b):
return a+b
print "import a, codes in a will run"
if __name__=='__main__':
print c
print add(10,20)
b.py:
#coding=utf-8
from a import *
c:\Python27\Scripts>python task_test.py
import a, codes in a will run
b.py:import 兩遍
#coding=utf-8
from a import *
from a import *
c:\Python27\Scripts>python task_test.py
import a, codes in a will run
只執行一次