1. 程式人生 > >python異常處理與除錯,正則表示式

python異常處理與除錯,正則表示式

####異常處理與除錯####

1.cacl包裡沒加if __name__ == "__main__":時,hell.py在呼叫mun中的方法時,會執行mun中的print,加了之後則沒有。

2.錯誤
•有的錯誤是程式編寫有問題造成的,比如本來應該輸出整數結果輸出了字元
串,這種錯誤我們通常稱之為 bug,bug 是必須修復的。
•有的錯誤是使用者輸入造成的,比如讓使用者輸入 email 地址,結果得到一個空字
符串,這種錯誤可以通過檢查使用者輸入來做相應的處理。
•還有一類錯誤是完全無法在程式執行過程中預測的,比如寫入檔案的時候,磁碟
滿了,寫不進去了,這類錯誤也稱為異常,在程式中通常是必須處理的,否則,程式會
因為各種問題終止並退出。

3.錯誤處理
• 在程式執行的過程中,如果發生了錯誤,可以事先約定返回一個錯誤程式碼;


• Python語言通常都內建了一套 try...except...finally... 的錯誤處理機制
try:
print 'try...'
r = 10 / 0
print 'result:', r
except ZeroDivisionError, e:
print 'except:', efinally:
print 'finally...'
print 'END'
- 用 try 來執行可能會出錯的程式碼;
- 如果執行正確,則except 語句塊不會執行;
- 如果執行錯誤,直接跳轉至錯誤處理程式碼,即except語句塊;
- 如果有 finally 語句塊,不管try語句塊內容是否正確,都會執行 finally語句塊
• 錯誤有很多種類,如果發生了不同型別的錯誤,應該由不同的 except語句塊處理。因此可以有多個 except 來捕獲不同型別的錯誤。
eroDivisionError:', e
print 'ValueError:', e
except ZeroDivisionError, e:
print 'ZeroDivisionError:', e
• Python 的錯誤其實也是 class,所有的錯誤型別都繼承自BaseException;
• 在使用except 捕獲該型別的錯誤,還把其子類也“一網打盡”;
•常見的錯誤型別和繼承關係看這裡:
https://docs.python.org/2/library/exceptions.html#exception­hierarchy


4.讀懂複雜的錯誤
•解讀錯誤資訊是定位錯誤的關鍵。我們從上往下可以看到整個錯誤的呼叫函式鏈。
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
bar('0')
main()


5.記錄錯誤
• 不捕獲錯誤,Python 直譯器會打印出錯誤資訊,但程式也被結束;
• 捕獲錯誤,就可以把錯誤資訊打印出來,然後分析錯誤原因,同時,讓程式繼續執行下去。
• Python 內建的 logging 模組可以記錄錯誤資訊。
logging.exception(e)


6.丟擲錯誤
• 錯誤是 class,捕獲一個錯誤就是捕獲到該 class 的一個例項;


• Python 的內建函式會丟擲很多型別的錯誤,我們自己編寫的函式也可以丟擲錯誤。
• 可以定義一個錯誤的 class,選擇好繼承關係,然後,用raise 語句丟擲一個錯誤的例項;
• 儘量使用 Python 內建的錯誤型別丟擲錯誤
class FooError(StandardError):
pass
def foo(s):
n = int(s)
if n==0:
raise FooError('invalid value: %s' % s)
return 10 / n

7.除錯- print
第一種方法簡單直接粗暴有效,就是用 print 把可能有問題的變數打印出來看看。用 print 最大的壞處是將來還得刪掉它,執行結果也會包含很多垃圾資訊。

8.除錯- 斷言
• 凡是用 print 來輔助檢視的地方,都可以用斷言(assert)來替代:;
• 如果斷言失敗, assert 語句本身就會丟擲 AssertionError


assert n!=0
assert hello() = "hello"
• Python 直譯器執行時可以用 -O 引數來關閉 assert,把所有的 assert 語句當成 pass。


9.除錯- logging
• logging 不會丟擲錯誤,而且可以輸出到檔案;
• logging.info() 就可以輸出一段文字到日誌檔案中。
• logging.basicConfig(level=logging.INFO)指定記錄資訊的級別,有debug , info , warning , error等幾個級別。
import logging
s = '0'
n = int(s)
logging.basicConfig(filename="/home/kiosk/hello.log
",level=logging.INFO)
logging.info('n=%d' %n)
print 10/n


10.除錯- pdb
•pdb
pdb讓程式以單步方式執行,隨時檢視執行狀態。n 可以單步執行程式碼,p 變數名 來檢視變數,q 結束除錯,退出程式。


•pdb.set_trace
在可能出錯的地方放一個 pdb.set_trace() ,就可以設定一個斷點。程式會自動在在 pdb.set_trace() 暫停並進入 pdb 除錯環境, p 檢視變數, c 繼續運
行。

####正則表示式####


1.正則表示式
是一種用來匹配字串的強有力的武器。
它的設計思想是用一種描述性的語言來給字串定義一個規則,凡是符合規則的字串,我們就認為它“匹配”了,
否則,該字串就是不合法的。

2.基本模式
• 字面模式: 就是字面長量,就代表其本身
• . 匹配任何字元
• \w 匹配一個單詞(字母) \W 匹配非字母
• \s 匹配空白 \S 匹配非空白字元
• \d 匹配數字
• ^ 開頭 $ 結尾
• \ 轉義字元


3.次數的匹配
次數的匹配 , 匹配其前面的字元出現的次數 :
• * 0 次或多次
• + 一次或多次
• ? 零次或一次
• {n} 出現 n 次
• {m,n} 出現 m 到 n 次


4.中括號
• 中括號用於指向一個字元集合
• 中括號可以使用元字元
• 中括號中的. 表示其字面意思
[a-z] [A-Z] [0-9] [A-Za-z]中括號
• [0-9a-zA-Z\_] 可以匹配一個數字、字母或者下劃線;
• [0-9a-zA-Z\_]+ 可以匹配至少由一個數字、字母或者下劃線組成的字串;
• [a-zA-Z\_][0-9a-zA-Z\_]{0, 19} 更精確地限制了變數的長度是 1­20個字元;
•A|B 可以匹配 A 或 B
•^\d 表示必須以數字開頭
• \d$ 表示必須以數字結束思考


• 判斷一個字串是否是合法的 Email 的方法;

判斷滿足029-1234567這樣要求的電話號碼的方法;


5.re 模組
r = r'hello'
re.match(r, 'hello')
re.match(r, 'westos')
match() 方法判斷是否匹配,如果匹配成功,返回一個 Match物件,否則返回 None 。

6.分組
m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
m.group(0)
m.group(1)
m.group(2)

7.貪婪匹配
正則匹配預設是貪婪匹配,也就是匹配儘可能多的字元
>>> re.match(r'^(\d+)(0*)$', '102300').groups()
('102300', '')
• \d+ 採用貪婪匹配,直接把後面的 0 全部匹配了,結果 0* 只能匹配空字串
• 必須讓 \d+ 採用非貪婪匹配(也就是儘可能少匹配),才能把後面的 0 匹配出來,加個 ? 就可以讓 \d+ 採用非貪婪匹配

8.編譯
當我們在 Python 中使用正則表示式時,re 模組內部會幹兩件事情:
1. 編譯正則表示式,如果正則表示式的字串本身不合法,會報錯;
2. 用編譯後的正則表示式去匹配字串。
重複使用幾千次,出於效率的考慮,我們可以預編譯該正則表示式。
r = r'hello'
r_compile = r.compile(r)
r_compile .match()


練習
基礎版:有一個日誌檔案access.log,統計訪問前十的 IP 地址和訪問次數。
升級版:有多個日誌檔案access.log,統計訪問前十的 IP 地址和訪問次數。

9.總結
• re.match(p,text) :p 為正則表示式模式, text 要查詢的字串,會返回一個match 物件


• re.search(p,text) : 只要在 text 中匹配到了 p 就返回,只返回第一個匹配到的


• re.findall(p,text) :將能匹配上的全返回,會返回一個 list
• re.split(p,text) : 按照 p 匹配,並且以匹配到的字元為分隔符切割 text, 返回一個切割後的 list


• re.sub(p,s,text) : 替換,將 p 匹配到的字元替換為 s.

re.finditer


• pattern = re.compile(p) 先編譯 p 模式,當正則表示式模式比較複雜的時候,會先編譯,然後再使用

eg:

1>

2>