)
大伙平常在读写文件之际肯定都见识过 with open() , 这便是最为经典的上下文管理器。在本节课当中要将 with 的底层原理彻彻底底弄明白, 学会自行去封装资源管理器, 这是开发项目时必须要掌握的知识点。一、为什么需要with语句日常读取文件传统写法data f.read()f.close()问题: 要是read()在进行当中出现报错情况, 代码会发生中断, close()就不会被执行了, 且文件资源无法被释放出来, 从而造成资源泄露了。于是有人用 try... 解决f open(test.txt, r, utf-8)try:data f.read():# 无论正常运行还是报错一定会执行关闭f.close()代码冗长重复度极高。通过with语句, 其本质实际上就是try -的语法糖现象, 能够给我们自动完成释放资源的操作。标准推荐写法data f.read()# 离开代码块自动执行close()无需手动关闭二、上下文管理器协议核心原理一个对象能够被 with 调用必须实现两个魔法方法1. (self)进入with代码块时自动执行返回值赋值给 as 后的变量2. (self, , , )带有代码块一旦离开, 就会自动执行。不管是正常结束, 还是代码出现异常, 都会将其触发, 而这样是用来清理资源的。案例自定义计时器管理器timeclass Timer:def (self):self.start time.()print(开始执行任务)selfdef (self, , , ):end time.()首先, 打印格式化字符串, 其中包含“任务结束”, 以及“耗时: ”, 再加上结束时间与开始时间相减后保留两位小数的结果, 以“秒”为单位。# 使用with Timer():time.sleep(1.2)print(正在运行业务代码)运行观察不管内部代码是否报错最终都会打印耗时。补充 三个参数异常类型、异常对象、异常堆栈。要是方法返回True, 那么代码块内抛出的异常会被屏蔽要是返回False, 异常将继续向外抛出。三、简化写法装饰器每一次去书写类以及魔法方法的时候, 都是比较麻烦的, 内置了点, 仅仅只是使用生成器来快速对上下文管理器进行创建。语法规则- yield之前对应 逻辑- yield之后对应 清理逻辑- yield的值就是as接收的变量fromtimedef timer():start time.()try:yield # 交出控制权执行with内部代码:end time.()把end减去start的结果, 保留两位小数, 以秒为单位, 用格式化字符串的写法, 输出“执行耗时: ”加上这个结果, 然后打印出来。# 调用with timer():time.sleep(0.8)print(测试代码)改造支持向外传递变量fromdef (name):print(f【进入】{name})yield f传入参数{name}print(f【退出】{name})with (数据处理) as val:print(val)print(执行业务逻辑)四、实际开发常用场景1. 文件读写最常用f.write(hello )2. 数据库连接自动关闭连接、事务回滚3. 线程锁自动释放锁4. 临时修改环境、临时切换目录执行完毕自动恢复5. 请求会话管理五、多个with嵌套写法方式1连续书写推荐使用打开文件操作, 以“a.txt”为文件名作为文件对象f1打开, 同时, 以“b.txt”为文件名作为文件对象f2打开。print(f1.read(), f2.read())方式2多层缩进with open(a.txt) as f1:with open(b.txt) as f2:pass六、常见坑点1. 切勿于with的内部情形之下, 对as所指示的变量进行再次赋值这一行为, 否则将会致使资源不能够依照正常的状况予以释放。2. yield过后的代码务必得编写于内部之中, 以此确保在发生异常的状况下依旧能够执行清理操作。3. 上下文管理器只作用于缩进内代码退出缩进立刻清理资源4. 猎取异常之时, 不得随意以True去遮蔽失误, 因其极易将程序漏洞隐匿起来。七、课后练习1. 以类的形式, 撰一个文件开启管理器, 自行开启、关上文件。2. 借由 去达成一个数据库模拟连接管理器, 当进入之时打印连接成功, 在退出之际打印关闭连接。3. 思考对比手动try-和with分别适合什么场景