上下文管理器context manager
-为什么要学context manager?
·类似于decorator,TensorFlow里面出现了不少context manager
·Pythonic的代码复用工具,适用于所有有始必有终模式的代码复用
·减少错误,降低编写代码的认知资源(比如打开文件需要关闭文件)
·提高代码可读性
-context manager与decorator之间的关系
·如果说decorator是对function和class的wrapper,那么context manager就是对任意形式的code block的wrapper
1.什么是context manager?与with语句是何关系?
context manager is a protocol for python with statement
执行时机:(双下划綫很不友好,不用代码表示会被认为是强调。。。)
·__init__():进入with语句时执行(optional,可实现也可不实现)
·__enter__():进入with代码块之前执行
·__exit__():离开with代码块之后执行
方法参数:
·__init__():context manager的初始化参数,自行定义
·__enter__():无参数
·__exit__():三个位置参数(type,instance,traceback)
说明:如果没有exception抛出,__exit__()的三个位置参数置为None
context manager通用结构:
class Foo:
def __init__(self,stable=False):
self.x = 0
self.stable = stable
print("__init__() called.")
def __enter__(self):
print("__enter__() called.")
return self
def __exit__(self,exc_type,exc_value,exc_traceback):
print("__exit__() called.")
if exc_type:
print(f'exc_type:{exc_type}')
print(f'exc_value:{exc_value}')
print(f'exc_traceback:{exc_traceback}')
if self.stable:#当stable=True时,即使出现异常也是返回True,也就是说抑制异常
return True
def add_one(self):
self.x += 1
def show_x(self):
print(self.x)
def main():
foo_cm_l = Foo()
print('hello!')
with foo_cm_l as foo_cm:
foo_cm.show_x()
foo_cm.add_one()
foo_cm.show_x()
print('hello')
with Foo() as foo_cm:
foo_cm.show_x()
foo_cm.add_one()
foo_cm.show_x()
print('hello')
with foo_cm_l as foo_cm:
foo_cm.show_x()
foo_cm.add_one()
foo_cm.show_x()
print('hello')
with Foo(True) as foo_cm:
1 / 0
print('hello')
with foo_cm_l as foo_cm:
1 / 0
if name == ‘main’:
main()
#以上代码的目的是为了看i)异常能否被抑制 ii)生命周期 结果如下
__init__() called.
hello!
__enter__() called.
0
1
__exit__() called.
hello
__init__() called.
__enter__() called.
0
1
__exit__() called.
hello
__enter__() called.
1
2
__exit__() called.
hello---
__init__() called.
__enter__() called.
__exit__() called.
exc_type:
exc_value:division by zero
exc_traceback:
hello----
__enter__() called.
__exit__() called.
exc_type:
exc_value:division by zero
exc_traceback:
Traceback (most recent call last):
File "t.py", line 59, in
main()
File "t.py", line 56, in main
1 / 0
ZeroDivisionError: division by zero
2.context manager如何使用
·成对出现的模式——上下文管理器使用的信号:
-open-close
-setup-teardown
-lock-release
-change-reset
-enter-exit
-start-stop
-create-Delete
f = open() ---> f.close()
with open(path,mode) as f:
f.read()
#这里就不用管f.close()了,因为在退出的时候,会自动调用
2)确保不同线程之间访问共享资源时的线程锁一定会释放
with threading.RLock():
access_resource()
#同理,会自动释放
3)管理数据库的连接资源
conn = sqlite3.connect()
with conn:
conn.execute("some SQL operations")
conn.execute("some other SQL operations")
#会自动调用commit函数,断开连接等等
4)对某一块代码进行运行时间测量:
import time
class Timer:
def __init__(self,name):
self.name = name
def __enter__(self):
self.start = time.time()
def __exit__(self,*args):
self.end = time.time()
self.interval = self.end - self.start
print("%s took: %0.3f seconds" % (self.name,self.interval))
return False
with Timer('fetching google homepage'):
conn = httplib.HTTPConnection('google.com')
conn.request('GET','/')
3.一个功能的代码实现与其工程化的区别
·某种或某些情况下可用vs任何情况下都可用
·资源足够的情况下可用vs有限的资源下可用
·自己可以运行起该程序vs任何人可自行运行
·自己可以继续开发修改vs任何人可继续开发修改
·强调功能本身vs强调:可用性、可扩展、性能、资源占用、安全、快速开发、容易交接、不易犯错