1. 程式人生 > >python教程13、異常處理(__import__, hasatter,getatter,setatter)

python教程13、異常處理(__import__, hasatter,getatter,setatter)

一、異常處理

python異常:
  python的執行時錯誤稱作異常
  (1)語法錯誤:軟體的結構上有錯誤而導致不能被直譯器解釋或不能被編譯器編譯
  (2)邏輯錯誤:由於不完整或不合法的輸入所致,也可能是邏輯無法生成、計算或者輸出結果需要的過程無法執行等

python異常是一個物件,表示錯誤或意外情況
  (1)在python檢測到一個錯誤時,將觸發一個異常
    python可以通常異常傳導機制傳遞一個異常物件,發出一個異常情況出現的訊號
    程式設計師也可以在程式碼中手動觸發異常
  (2)python異常也可以理解為:程式出現了錯誤而在正常控制流以外採取的行為
    第一階段:直譯器觸發異常,此時當前程式流將被打斷
    第二階段:異常處理,如忽略非致命錯誤、減輕錯誤帶來的影響等

檢測和處理異常:
  (1)異常通過try語句來檢測
    任何在try語句塊裡的程式碼都會被檢測,以檢查有無異常發生
  (2)try語句主要有兩種形式:
    try-except: 檢測和處理異常
      可以有多個except
      支援使用else子句處理沒有探測異常的執行的程式碼
    try-finally: 僅檢查異常並做一些必要的清理工作
      僅能有一個finally
  (3)try語句的複合形式:
    try-execpt-else-finally

 

1、異常基礎

在程式設計過程中為了增加友好性,在程式出現bug時一般不會將錯誤資訊顯示給使用者,而是現實一個提示的頁面,通俗來說就是不讓使用者看見大黃頁!!!

1 2 3 4 try :      pass except  Exception as ex:  
     pass

#python3.x中是這麼寫的,python2.x是這麼寫的:  except Exception,e:

需求:將使用者輸入的兩個數字相加  

複製程式碼
while True:
    num1 = raw_input('num1:')
    num2 = raw_input('num2:')
    try:
        num1 = int(num1)
        num2 = int(num2)
        result = num1 + num2
    except Exception as e:
        print('出現異常,資訊如下:')
        print(e)
複製程式碼

2、異常種類

python中的異常種類非常多,每個異常專門用於處理某一項異常!!!

複製程式碼
AssertionError: 斷言語句失敗
AttributeError: 屬性引用或賦值失敗
FloatingPointError: 浮點型運算失敗
IOError:  I/O操作失敗
ImportError: import語句不能找到要匯入的模組,或者不能找到該模組特別請求的名稱
IndentationError: 解析器遇到了一個由於錯誤的縮排而引發的語法錯誤
IndexError: 用來索引序列的證書超出了範圍
KeyError: 用來索引對映的鍵不再對映中
keyboardInterrupt: 使用者按了中斷鍵(Ctrl+c,Ctrl+Break或Delete鍵)
MemoryError: 運算耗盡記憶體
NameError: 引用了一個不存在的變數名
NotImplementedError: 由抽象基類引發的異常,用於指示一個具體的子類必須覆蓋一個方法
OSError: 由模組os中的函式引發的異常,用來指示平臺相關的錯誤
OverflowError: 整數運算的結果太大導致溢位
SyntaxError: 語法錯誤
SystemError: python本身或某些擴充套件模組中的內部錯誤
TypeError:對某物件執行了不支援的操作
UnboundLocalError:引用未繫結值的本地變數
UnicodeError:在Unicode的字串之間進行轉換時發生的錯誤
ValueError:應用於某個物件的操作或函式,這個物件具有正確的型別,但確有不適當的值
WindowsError:模組os中的函式引發的異常,用來指示與WIndows相關的錯誤
ZeroDivisionError: 除數為0
複製程式碼   更多異常

例項:IndexError

dic = ["python", 'linux']
try:
    dic[10]
except IndexError as e:
    print(e)

例項:KeyError

dic = {'k1':'v1'}
try:
    dic['k20']
except KeyError as e:
    print(e)

對於上述例項,異常類只能用來處理指定的異常情況,如果非指定異常則無法處理。

1 2 3 4 5 6 7 # 未捕獲到異常,程式直接報錯    s1  =  'hello' try :      int (s1) except  IndexError as e:      print (e)

所以,寫程式時需要考慮到try程式碼塊中可能出現的任意異常,可以這樣寫:  

1 2 3 4 5 6 7 8 9 s1  =  'hello' try :      int (s1) except  IndexError as e:      print (e) except  KeyError as e:      print (e) except  ValueError as e:      print (e)

萬能異常 在python的異常中,有一個萬能異常:Exception,他可以捕獲任意異常,即:  

1 2 3 4 5 s1  =  'hello' try :      int (s1) except  Exception as e:      print (e)

接下來你可能要問了,既然有這個萬能異常,其他異常是不是就可以忽略了!

答:當然不是,對於特殊處理或提醒的異常需要先定義,最後定義Exception來確保程式正常執行

1 2 3 4 5 6 7 8 9 s1  =  'hello' try :      int (s1) except  KeyError as e:      print ( '鍵錯誤' ) except  IndexError as e:      print ( '索引錯誤' ) except  Exception as e:      print ( '錯誤' )

3、異常其他結構  

1 2 3 4 5 6 7 8 9 10 11 12 try :      # 主程式碼塊      pass except  KeyError as e:      # 異常時,執行該塊      pass else :      # 主程式碼塊執行完,執行該塊      pass finally :      # 無論異常與否,最終執行該塊      pass

4、主動觸發異常  

1 2 3 4 try :      raise  Exception( '錯誤了。。。' ) except  Exception as e:      print (e)

5、自定義異常  

1 2 3 4 5 6 7 8 9 10 11 12 class  MyException(Exception):         def  __init__( self , msg):          self .message  =  msg         def  __str__( self ):          return  self .message    try :      raise  MyException( '我的異常' ) except  WupeiqiException as e:      print (e)

6、斷言  

1 2 3 4 5 # assert 條件    assert  1  = =  1    assert  1  = =  2

二、反射

  python中的反射功能是由以下四個內建函式提供:hasattr、getattr、setattr、delattr、__import__(module_name),改四個函式分別用於對物件內部執行:檢查是否含有某成員、獲取成員、設定成員、刪除成員、匯入模組以字串方式匯入。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class  Foo( object ):         def  __init__( self ):          self .name  =  'python'         def  func( self ):          return  'func'    obj  =  Foo()    # #### 檢查是否含有成員 #### hasattr (obj,  'name' ) hasattr (obj,  'func' )    # #### 獲取成員 #### getattr (obj,  'name' ) getattr (obj,  'func' )    # #### 設定成員 #### setattr (obj,  'age' 18 ) setattr (obj,  'show' lambda  num: num  +  1 )    # #### 刪除成員 #### delattr (obj,  'name' ) delattr (obj,  'func' )

詳細解析:

當我們要訪問一個物件的成員時,應該是這樣操作:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 class  Foo( object ):         def  __init__( self ):          self .name  =  'python'         def  func( self ):          return  'func'    obj  =  Foo()    # 訪問欄位 obj.name # 執行方法 obj.func()
那麼問題來了? a、上述訪問物件成員的 name 和 func 是什麼?  答:是變數名 b、obj.xxx 是什麼意思?  答:obj.xxx 表示去obj中或類中尋找變數名 xxx,並獲取對應記憶體地址中的內容。 c、需求:請使用其他方式獲取obj物件中的name變數指向記憶體中的值 “python” 複製程式碼
class Foo(object):
 
    def __init__(self):
        self.name = 'python'
 
# 不允許使用 obj.name
obj = Foo()
複製程式碼

答:有兩種方式,如下:

複製程式碼
class Foo(object):

    def __init__(self):
        self.name = 'python'

    def func(self):
        return 'func'

# 不允許使用 obj.name
obj = Foo()

print obj.__dict__['name']
複製程式碼

第二種:

複製程式碼
class Foo(object):

    def __init__(self):
        self.name = 'python'

    def func(self):
        return 'func'

# 不允許使用 obj.name
obj = Foo()

print getattr(obj, 'name')
複製程式碼

d、比較三種訪問方式

  • obj.name
  • obj.__dict__['name']
  • getattr(obj, 'name')

答:第一種和其他種比,...
      第二種和第三種比,...

複製程式碼
#!/usr/bin/env python
#coding:utf-8
from wsgiref.simple_server import make_server

class Handler(object):

    def index(self):
        return 'index'

    def news(self):
        return 'news'


def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    url = environ['PATH_INFO']
    temp = url.split('/')[1]
    obj = Handler()
    is_exist = hasattr(obj, temp)
    if is_exist:
        func = getattr(obj, temp)
        ret = func()
        return ret
    else:
        return '404 not found'

if __name__ == '__main__':
    httpd = make_server('', 8001, RunServer)
    print "Serving HTTP on port 8000..."
    httpd.serve_forever()
複製程式碼

結論:反射是通過字串的形式操作物件相關的成員。一切事物都是物件!!!

  

類也是物件

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class  Foo( object ):         staticField  =  "old boy"         def  __init__( self ):          self .name  =  'wupeiqi'         def  func( self ):          return  'func'         @staticmethod      def  bar():          return  'bar'    print  getattr (Foo,  'staticField' ) print  getattr (Foo,  'func' ) print  getattr (Foo,  'bar' )

模組也是物件

home.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def dev():
    return 'dev'

 index.py

複製程式碼
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
"""
程式目錄:
    home.py
    index.py
 
當前檔案:
    index.py
"""
 
 
import home as obj
 
#obj.dev()
 
func = getattr(obj, 'dev')
func() 
複製程式碼

兩個例子:

第一個例子:模組和主程式在同一目錄

home.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def index():
    print("炫酷的主頁面")

index.py

複製程式碼
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 反射:基於字串的形式去物件(模組)中操作其成員getattr(),setattr(),hasattr(),delattr()
# 擴充套件:匯入模組
#      import xxx
#      from xxx import ooo
#
#      obj = __import__("xxx")
#      obj = __import__("xxx." + ooo,fromlist=True)


def run():
    while True:
        inp = input("請輸入要訪問的URL:")
        mo,fn = inp.split('/')
        obj = __import__(mo)
        if hasattr(obj,fn):
            func = getattr(obj,fn)
            func()
        else:
            print("網頁不存在")

run()
複製程式碼

執行的時候輸入URL:home/index   這樣就執行了home模組下的index函式

第二個例子:模組和主程式不在同一目錄

lib/account.py  

複製程式碼
#!/usr/bin/env python
# -*- coding:utf-8 -*-

def login():
    print("炫酷的登入頁面")


def logout():
    print("炫酷的退出頁面")
複製程式碼

index1.py

複製程式碼
#!/usr/bin/env python
# -*- coding:utf-8 -*-

# 反射:基於字串的形式去物件(模組)中操作其成員getattr(),setattr(),hasattr(),delattr()
# 擴充套件:匯入模組
#      import xxx
#      from xxx import ooo
#
#      obj = __import__("xxx")
#      obj = __import__("xxx." + ooo,fromlist=True)

def run():
    while True:
        inp = input("請輸入要訪問的URL:")
        mo,fn = inp.split('/')
        obj = __import__("lib." + mo,fromlist=True)
        if hasattr(obj,fn):
            func = getattr(obj,fn)
            func()
        else:
            print("網頁不存在")


run()
複製程式碼

執行的時候輸入URL:account/login 這樣就執行了lib/account下的login函式

 

### 另外一種實現方式

index2.py

1 2 3 4 5 6 7 8 import  importlib   module  =  "lib.account" func_name  =  "login"   =  importlib.import_module(module) func  =  getattr (m, func_name) func()