一、簡介
with是從Python 2.5 引入的一個新的語法,更準確的說,是一種上下文的管理協議,用于簡化try…except…finally的處理流程。with通過__enter__方法初始化,然后在__exit__中做善后以及處理異常。對于一些需要預先設置,事后要清理的一些任務,with提供了一種非常方便的表達。
with的基本語法如下,EXPR是一個任意表達式,VAR是一個單一的變量(可以是tuple),”as VAR”是可選的。
代碼如下:
with EXPR as VAR:
BLOCK
根據PEP 343的解釋,with…as…會被翻譯成以下語句:
代碼如下:
mgr = (EXPR)
exit = type(mgr).__exit__ # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
try:
VAR = value # Only if "as VAR" is present
BLOCK
except:
# The exceptional case is handled here
exc = False
if not exit(mgr, *sys.exc_info()):
raise
# The exception is swallowed if exit() returns true
finally:
# The normal and non-local-goto cases are handled here
if exc:
exit(mgr, None, None, None)
為什么這么復雜呢?注意finally中的代碼,需要BLOCK被執行后才會執行finally的清理工作,因為當EXPR執行時拋出異常,訪問mgr.exit執行就會報AttributeError的錯誤。
二、實現方式
根據前面對with的翻譯可以看到,被with求值的對象必須有一個__enter__方法和一個__exit__方法。稍微看一個文件讀取的例子吧,注意在這里我們要解決2個問題:文件讀取異常,讀取完畢后關閉文件句柄。用try…except一般會這樣寫:
代碼如下:
f = open('/tmp/tmp.txt')
try:
for line in f.readlines():
print(line)
finally:
f.close()
注意我們這里沒有處理文件打開失敗的IOError,上面的寫法可以正常工作,但是對于每個打開的文件,我們都要手動關閉文件句柄。如果要使用with來實現上述功能,需要需要一個代理類:
代碼如下:
class opened(object):
def __init__(self, name):
self.handle = open(name)
def __enter__(self):
return self.handle
def __exit__(self, type, value, trackback):
self.handle.close()
with opened('/tmp/a.txt') as f:
for line in f.readlines():
新聞熱點
疑難解答