1. 程式人生 > >(轉)Python自動化運維之13、異常處理及反射(__import__,getattr,hasattr,setattr)

(轉)Python自動化運維之13、異常處理及反射(__import__,getattr,hasattr,setattr)

邏輯 斷言 函數 typeerror 代碼 __init__ raw linu 基類

Python自動化運維之13、異常處理及反射(__import__,getattr,hasattr,setattr)

一、異常處理

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函數

(轉)Python自動化運維之13、異常處理及反射(__import__,getattr,hasattr,setattr)