Python with語句定義及使用
如果你有一些物件(比如一個檔案、網路連線或鎖),需要支援 with 語句,下面介紹兩種定義方法。
方法(1):
首先介紹下with 工作原理
(1)緊跟with後面的語句被求值後,返回物件的“__enter__()
”方法被呼叫,這個方法的返回值將被賦值給as後面的變數;
(2)當with後面的程式碼塊全部被執行完之後,將呼叫前面返回物件的“__exit__()
”方法。
with工作原理程式碼示例:
class Sample:
def __enter__(self):
print "in __enter__"
return "Foo"
def __exit__(self, exc_type, exc_val, exc_tb):
print "in __exit__"
def get_sample():
return Sample()
with get_sample() as sample:
print "Sample: ", sample
程式碼的執行結果如下:
in __enter__
Sample: Foo
in __exit__
可以看到,整個執行過程如下:
(1)enter()方法被執行;
(2)enter()方法的返回值,在這個例子中是”Foo”,賦值給變數sample;
(3)執行程式碼塊,列印sample變數的值為”Foo”;
(4)exit()方法被呼叫;
【注:】exit()方法中有3個引數, exc_type, exc_val, exc_tb,這些引數在異常處理中相當有用。
exc_type: 錯誤的型別
exc_val: 錯誤型別對應的值
exc_tb: 程式碼中錯誤發生的位置
示例程式碼:
class Sample():
def __enter__(self):
print('in enter')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print "type: ", exc_type
print "val: ", exc_val
print "tb: ", exc_tb
def do_something(self):
bar = 1 / 0
return bar + 10
with Sample() as sample:
sample.do_something()
程式輸出結果:
in enter
Traceback (most recent call last):
type: <type 'exceptions.ZeroDivisionError'>
val: integer division or modulo by zero
File "/home/user/cltdevelop/Code/TF_Practice_2017_06_06/with_test.py", line 36, in <module>
tb: <traceback object at 0x7f9e13fc6050>
sample.do_something()
File "/home/user/cltdevelop/Code/TF_Practice_2017_06_06/with_test.py", line 32, in do_something
bar = 1 / 0
ZeroDivisionError: integer division or modulo by zero
Process finished with exit code 1
方法(2):
實現一個新的上下文管理器的最簡單的方法就是使用 contexlib 模組中的 @contextmanager 裝飾器。 下面是一個實現了程式碼塊計時功能的上下文管理器例子:
import time
from contextlib import contextmanager
@contextmanager
def timethis(label):
start = time.time()
try:
yield
finally:
end = time.time()
print('{}: {}'.format(label, end - start))
# Example use
with timethis('counting'):
n = 10000000
while n > 0:
n -= 1
在函式 timethis() 中,yield 之前的程式碼會在上下文管理器中作為 __enter__()
方法執行, 所有在 yield 之後的程式碼會作為 __exit__()
方法執行。 如果出現了異常,異常會在yield語句那裡丟擲。
【注】
1、@contextmanager 應該僅僅用來寫自包含的上下文管理函式。
2、如果你有一些物件(比如一個檔案、網路連線或鎖),需要支援 with 語句,那麼你就需要單獨實現 __enter__()
方法和 __exit__()
方法。