例子一
首先來看一段代碼:
class Foo(object): def __init__(self): print('實例化一個對象') def __enter__(self): print('進入')
def __exit__(self, exc_type, exc_val, exc_tb): print('退出') obj = Foo() with obj: print('正在執行')
上面代碼執行結果為:
實例化一個對象
進入
正在執行
退出
結論1
我們知道,實例化Foo,得到obj對象,會執行Foo的__init__方法,也就是打印了第一句;
按照,程序從上至下執行,應該會打印“正在執行”才對,為什么會在它之前先打印了進入,在它之后打印了退出呢?
因為我們在定義Foo時,定義了__enter__和__exit__方法,那么我們實例化的對象obj就是一個上下文管理器,
即含有__enter__和__exit__方法的對象就是上下文管理器。
with 上下文管理器:
語句體
當with遇到上下文管理器,就會在執行語句體之前,先執行上下文管理器的__enter__方法,然后再執行語句體,執行完語句體后,最后執行__exit__方法
這也就是為什么會出現文章開頭的情況的原因。
例子二
再看看這段代碼:
class Foo(object): def __init__(self): print('實例化一個對象') def __enter__(self): print('進入') def __exit__(self, exc_type, exc_val, exc_tb): print('退出')
# return True obj = Foo() with obj: raise ImportError print('正在執行')
結果如下:

把上面代碼中我們注釋掉的那一行代碼取消注釋,結果如下

我們會發現,雖然我們故意在語句體中拋出一個錯誤,按照正常情況,執行到報錯地方就不會執行了,而__exit__是在語句體執行完之后執行的,但還是執行了__exit__方法;當我們在__exit__中給一個返回值為Ture時,就會忽略錯誤。
結論2
所有我們可以發現
with語句類似
try :
except:
finally:
的功能:但是with語句更簡潔。而且更安全。代碼量更少。
出現異常時,如果 __exit__ 返回 False(默認不寫返回值時,即為False),則會重新拋出異常,讓with 之外的語句邏輯來處理異常,這也是通用做法;如果返回 True,則忽略異常,不再對異常進行處理
例子三
class Foo(object): def __init__(self): print('實例化一個對象') def __enter__(self): print('進入') # return self def __exit__(self, exc_type, exc_val, exc_tb): print('退出') with Foo() as obj: print(obj,type(obj)) print('正在執行')

把上面代碼中我們注釋掉的那一行代碼取消注釋,結果如下

結論
調用上下文管理器的 __enter__ 方法時;如果使用了 as 子句,則將 __enter__() 方法的返回值賦值給 as 子句中的目標
with 上下文管理器 as target:
代碼語句體
with后面必須跟一個上下文管理器,如果使用了as,則是把上下文管理器的 __enter__() 方法的返回值賦值給 target,target 可以是單個變量,或者由“()”括起來的元組(不能是僅僅由“,”分隔的變量列表,必須加“()”)
例子四
我們經常會看到這樣的代碼:
with open("/tmp/foo.txt") as file: data = file.read()
結論
這里使用了 with 語句,不管在處理文件過程中是否發生異常,都能保證 with 語句執行完畢后已經關閉了打開的文件句柄。如果使用傳統的 try/finally 范式,則要使用類似如下代碼:
somefile = open(r'somefileName') try: for line in somefile: print line # ...more code finally: somefile.close()
比較起來,使用 with 語句可以減少編碼量。已經加入對上下文管理協議支持的還有模塊 threading、decimal 等。
補充
with只能配合上下文管理器使用,常見的上下文管理器有
file
decimal.Context
thread.LockType
threading.Lock
threading.RLock
threading.Condition
threading.Semaphore
threading.BoundedSemaphore
