python上下文管理__exit__,___enter___方法-通透式讲解-附加练习-附加代码注释-源码解读

Carnelian ·
更新时间:2024-11-14
· 758 次阅读

上下文管理作用:

他能帮助我们,在打开一个资源的同时帮我们把资源清除掉
我们来敲一个小demo来看一下效果

import time class A: def __enter__(self): print("enter") def __exit__(self, exc_type, exc_val, exc_tb): print("exit") with A(): time.sleep(5) print("+++++++++") time.sleep(5)

返回结果
在这里插入图片描述
现在我们可以知道当进入with语句调用def enter(self),然后执行print("++++++"),出执行语句调用def exit(self, exc_type, exc_val,exc_tb)
这就是上下文管理运用的两个方法 enter,exit
这里要注意:当单独调用A()时上下文管理的两个方法不会起到任何作用,只有使用with后才会产生效果

这里我抛出一个问题,下面代码f == a 返回的是True还是False?

import time class A: def __enter__(self): print("enter") def __exit__(self, exc_type, exc_val, exc_tb): print("exit") f = A() with f as a: print(f == a)

在这里插入图片描述
运行代码我们发现返回的是False,a的值到底是什么那?我们分别打印一下f和a

import time class A: def __enter__(self): print("enter") # 他的返回值将成为as子句后面变量的值 def __exit__(self, exc_type, exc_val, exc_tb): print("exit") f = A() with f as a: print(f == a) print(f) print(a)

在这里插入图片描述
通过运行结果我们可以得到一个结论,a的值是上下文管理方法enter的返回值

exit(self, exc_type, exc_val, exc_tb)参数作用 class A: def __enter__(self): print("enter") def __exit__(self, exc_type, exc_val, exc_tb): print(exc_type) print(exc_val) print(exc_tb) print("exit") with A() : raise KeyError("Wrong")

运行结果:
在这里插入图片描述
总结以下几点内容:
在这里插入图片描述
注意点:如果__exit__方法返回的是一个等效为True的值,就会压制异常

class A: def __enter__(self): print("enter") def __exit__(self, exc_type, exc_val, exc_tb): print(exc_type) print(exc_val) print(exc_tb) return True # 等效为True with A() : raise KeyError("Wrong")

在这里插入图片描述
就可以看到没有红色的异常字体显示了
在这里插入图片描述
方法1.装饰器

import datetime import time import funtools def logger(fn): @funtools.wraps(fn) # wrapper = wrpas(fn)(wrapper) def wrapper(*args,**kwargs): start = datetime.datetime.now() ret = fn(*args,**kwargs) end = (datetime.datetime.now()-start).total_seconds() print(end) return ret return wrapper @logger # add = logger(add) def add(x:int,y:int): time.sleep(2) return x+y add(5,4)

方法2.上下文管理

import datetime import time class TimeIt: def __init__(self,fn,output=lambda fn,delta:print("{}:{}".format(fn.__name__,delta))): self.fn = fn self.output = output 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) self.output(self.fn,delta) def __call__(self, x,y): return self.fn(x,y) def add(x:int,y:int): time.sleep(2) return x+y with TimeIt(add) as obj: obj(5,6)

在这里插入图片描述
进阶版本:用类实现装饰

import datetime import time class TimeIt: def __init__(self,fn,output=lambda fn,delta:print("{}:{}".format(fn.__name__,delta))): self.fn = fn self.output = output # 因为这里我们不能使用@wraps所以我们只能把装饰器转换成他的等价式 wraps(fn)(self) # @wraps(fn) wrapper=wraps(fn)(wrapper) def __call__(self, x,y): start = datetime.datetime.now() ret = self.fn(x,y) delta = (datetime.datetime.now()-start).total_seconds() self.output(self.fn,delta) return ret @TimeIt # add = TimeIt(add) def add(x:int,y:int): time.sleep(2) return x+y add(4,6)

在这里插入图片描述

应用场景

在这里插入图片描述

扩展

了解即可,源代码中经常可见,要看了知道是做什么的
在这里插入图片描述
ctlr+鼠标右键进入源码
在这里插入图片描述
我们可以看到源码中很清楚的给了你一个经典的用法

from contextlib import contextmanager @contextmanager def a(): print("~~~~~~enter") # 相当于__enter__ try yield 500 # 相当于__enter__,return的值 finally print("-----exit") # 相当于__exit__ with a() as f: print(f)

返回结果
在这里插入图片描述


作者:Monster123$



exit 方法 enter 源码 Python

需要 登录 后方可回复, 如果你还没有账号请 注册新账号