上下文管理
- 当一个对象同时实现了__enter__()和__exit__()方法,它就属于上下文管理的对象
方法 | 意义 |
---|---|
__enter __ | 进入与此对象相关的上下文。如果存在该方法,with语法会把该方法的返回值作为绑定到as子句中指定的变量上 |
__exit __ | 退出与此对象相关的上下文。 |
import time
class Point:
def __init__(self):
print("1:init----------")
time.sleep(1)
print('init over')
def __enter__(self):
print('2,enter ~~~~~~~~')
return 1 # as 后面的标识符拿到的就是__enter__的返回值
def __exit__(self,exc_type,exc_val,exc_tb):
print('exit')
f = Point() # 实例化f的时候,并不进入__enter__
with Point() as p:
print('3 -----------')
----------------------------------------
1:init----------
init over
1:init----------
init over
2,enter ~~~~~~~~
3 -----------
exit
- 实例化对象的时候,并不会调用enter,进入with语句块调用__enter__方法,然后执行语句体,最后离开with语句块的时候,调用__exit__方法
- with 后面的对象必须有__enter__()方法和__exit__()方法,as后面的标识符拿到的是__enter__的返回值(with语法,会调用with后的对象的__enter__方法,如果有as,则将该方法的返回值赋给as子句的变量。)
- 异常需要在with语句块中处理,
在exit方法中有return,返回值等效bool值,等效False,将会把异常向外抛出,
等效True,异常被压制,不向外抛出
方法的参数
-
__enter__方法没有其他参数。
-
__exit__方法有3个参数: __exit __(self, exc_type, exc_value, traceback) 这三个参数都与异常有关。如果该上下文退出时没有异常,这3个参数都为None。如果有异常,参数意义如下
- exc_type,异常类型
- exc_value,异常的值
- traceback,异常的追踪信息
-
__exit__方法返回一个等效True的值,则压制异常;否则,继续抛出异常 如下
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
print(1,self)
def __enter__(self):
print('2 ------------')
return 1
def __exit__(sefl,exc_type, exc_val, exc_tb):
print(3,exc_type)
print(4,exc_val)
print(5,exc_tb)
return 1
def __str__(self):
return str((self.x,self.y))
with Point(2,3) as p:
a = 1/0 # 此处除0异常,本应该抛异常,但是__exit__()方法中有return值,且等效为True,所以异常被压制,因为异常,所以'pass'并不能打印
print(6,'pass')
------------------------------------------
1 (2, 3)
2 ------------
3 <class 'ZeroDivisionError'>
4 division by zero
5 <traceback object at 0x00000214DE0E7408>
实现类做装饰器和上下文管理增强功能
下面的类即可以用在上下文管理,又可以用做装饰器
import time
import datetime
class Timed:
"""this is decoration"""
def __init__(self, fn):
self.fn = fn
self.__doc__ = fn.__doc__ #实例属性更改应该在初始化配置的时候更改
self.__name__ = fn.__name__
def __enter__(self):
self.start = datetime.datetime.now()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
delta = (datetime.datetime.now() - self.start).total_seconds()
print("{} took {}s. context".format(self.fn.__name__, delta))
def __call__(self, *args, **kwargs): #实例功能的增加在函数调用的位置增加
start = datetime.datetime.now()
ret = self.fn(*args, **kwargs)
delta = (datetime.datetime.now() - start).total_seconds()
print(delta)
return ret
@Timed # add = Timed(add)
def add(x, y):
'''this is add function'''
time.sleep(1)
v = x + y
print(v)
return x + y
add(3, 6)
print(add.__doc__,";",add.__name__)
----------------------------------------------------------------
9
1.000373
this is add function ; add
- 上下文应用场景
- 增强功能在代码执行的前后增加代码,以增强其功能。类似装饰器的功能。
- 资源管理打开了资源需要关闭,例如文件对象、网络连接、数据库连接等
- 权限验证在执行代码之前,做权限的验证,在__enter__中处理