導語:本文章記錄了本人在學習Python基礎之控制流程篇的重點知識及我的心得,打算入門Python的朋友們能夠來一塊兒學習並交流。
本文重點:python
一、掌握if語句以外的else的用法;
二、掌握上下文管理器的定義、協議、使用和with塊;
三、掌握有用的@contextmanger裝飾器。
if/else中if和else是同級對立的語句,對立是指流程通過一層if/else語句只能對應一種處理語句。而else在for/else,while/else,try/else語句中的功能則大相徑庭。後者中的else功能以下:數據庫
for循環沒有被break語句停止才運行else塊。
while循環沒有被break語句停止才運行else塊。
try塊中,沒有異常拋出時才運行else塊。
下面以for/else爲例進行代碼實現:編程
for i in "apple": if i.isupper(): break else: raise ValueError('No upper string was found')
try/except不只用於處理錯誤,還用於處理錯誤,這屬於EAFP編程風格。app
即先假定存在有效的鍵或屬性,若是假定不成立,那麼捕獲異常。
即在調用函數或查找屬性或鍵以前顯式測試前提條件。
上下文管理器(context manger):在操做文件和創建數據庫鏈接的時候,咱們最終須要關閉資源,這就是上下文管理器存在的意義。上下文管理器協議:包含__enter__和__exit__兩個方法。
語法:try/finally模式和with語句
實例:try/finally模式函數
try: f = open('test.txt', 'a+') f.write('Foo\n') finally: f.close()
接下來咱們用with語句進行替換:
實例:with語句工具
with open('test.txt', 'a+') as f: f.write('Foo\n')
分析:open 的返回值賦值給變量 f,當離開 with 代碼塊的時候,系統會自動調用 f.close() 方法。總結:with塊的功能在於簡化try/finally模式。with語句在開始運行時會在上下文管理器對象上調用__enter__,而with語句結束時會調用__exit__方法。
Tips:with語句中的as語句是可選的,as語句將__enter__返回的值綁定到as語句後的變量。值得注意的是,對於open函數必須加上as字句來獲取文件的引用。學習
在掌握基本上下文管理器和with語句後,咱們經過自定義上下文管理器來深入認識with語句和__enter__以及__exit__的聯繫。
實例:自定義知足上下文管理器協議的類測試
class OpenFileDemo(object): def __init__(self, filename): self.filename = filename self.f = open(self.filename, 'a+') return self.f def __exit__(self, exc_type, exc_value, traceback): self.f.close() if exc_type != SyntaxError: return True return False with OpenFileDemo('test.txt') as f: f.write('Foo\n')
當上下文管理器遇到異常時由__exit__方法處理。傳給__exit__方法的三個參數以下:
exc_type:異常類(例如SyntaxError)。
exc_value:異常實例。有時會有參數傳給異常構造方法,例如錯誤信息,可使用exc_value.args獲取這些參數。
traceback:traceback對象。code
@contextmanger裝飾器是contextlib模塊中的工具,它能夠將包含yield的語句變成上下文管理器。
其中,yield以前的語句在__enter__方法中執行
,yield以後的語句在__exit__方法執行
,yield後面的值是函數的返回值,綁定到實際調用的with中的as子句的目標變量上
。
如此能夠避免編寫一個類來實現上下文管理器協議。對象
實例:@contextmanger裝飾器應用之計時器
import contextlib import time @contextlib.contextmanager def timer(): start=time.time() yield end=time.time() usedtime=end-start print('Running time was %r seconds'%usedtime) with timer() as usedtime: time.sleep(1)
注意:一旦with塊在調用timer出現異常時,拋出的異常會在timer函數中的yield表達式中再次拋出。若是timer函數沒有處理異常的代碼就會致使函數運行停止,系統處於無效狀態。所以必要時在上下文管理器函數中使用try/finally語句防範錯誤。
@contextmanger集合了三個不一樣的Python特性:函數裝飾器、生成器和with語句,很是實用!
最後說明contextlib模塊中包含的實用工具:
closing
: 若是對象提供了 close() 方法,但沒有實現 _enter__/__exit_ 協議,那麼可使用這個函數構建上下文管理器。suppress
: 構建臨時忽略指定異常的上下文管理器。@contextmanager
: 這個裝飾器把簡單的生成器函數變成上下文管理器,這樣就不用建立類去實現管理器協議了。ContextDecorator
: 這是個基類,用於定義基於類的上下文管理器。這種上下文管理器也能用於裝飾函數,在受管理的上下文中運行整個函數。ExitStack
: 這個上下文管理器能進入多個上下文管理器。with 塊結束時,ExitStack 按照後進先出的順序調用棧中各個上下文管理器的_exit_ 方法。若是事先不知道 with 塊要進入多少個上下文管理器,可使用這個類。例如,同時打開任意一個文件列表中的全部文件。顯然,在這些實用工具中,使用最普遍的是 @contextmanager 裝飾器,所以要格外留心。這個裝飾器也有迷惑人的一面,由於它與迭代無關,卻要使用 yield 語句。