Python中能否通过重写类属性让实例在with作用域退出前执行操作?
实现类的with语句自动清理操作
当然可以做到!Python里的with语句就是专门用来处理这种需要自动执行收尾操作的场景,它依赖的是上下文管理器协议——你只需要给你的类实现两个特殊方法:__enter__() 和 __exit__() 就行。
先搞懂这两个方法的作用:
__enter__():当程序进入with语句的作用域时,这个方法会被自动调用,它的返回值会被赋值给as后面的变量(比如你例子里的mw)。__exit__():不管是正常执行完with块里的代码,还是中途抛出异常,只要退出with作用域,这个方法就会被调用。我们刚好可以在这里放flush()和close()这类收尾逻辑。
修改你的MyWriter类:
下面是调整后的完整代码,我还顺便修正了原代码里的一个小问题(wb模式需要写入字节,所以flush时要对字符串编码):
class MyWriter(object): def __init__(self, path): self.f = open(path, 'wb') self.buffer = '' def __enter__(self): # 返回当前实例,这样with...as mw里的mw就是这个类的实例 return self def write(self, text): self.buffer += text # 缓存达到阈值时自动刷入文件 if len(self.buffer) >= 4096: self.flush() def flush(self): # 注意wb模式要写入字节,所以对字符串做encode self.f.write(self.buffer.encode()) self.buffer = '' def close(self): self.flush() self.f.close() def __exit__(self, exc_type, exc_val, exc_tb): # 不管有没有异常,都执行关闭操作 self.close() # 返回None(或False)表示不抑制异常,让异常正常传播 # 如果返回True,会把异常吞掉,一般不建议这么做 return None
怎么用?
现在你直接用你想要的写法就行:
PATH = "test.txt" with MyWriter(PATH) as mw: mw.write("SOME TEXT")
当代码执行完with块的内容(哪怕中间出了错),Python都会自动调用__exit__(),进而触发close(),帮你完成缓存刷入和文件关闭的操作。
额外小提示:
如果你觉得写两个特殊方法有点麻烦,也可以用contextlib模块的contextmanager装饰器来实现,但对于类来说,直接实现上下文管理器协议会更直观,也更容易维护~
内容的提问来源于stack exchange,提问作者Katie
相关产品推荐
相关产品推荐

