管理外部资源的背景

  • 在编程中会面临的一个常见问题是如何正确管理外部资源,例如文件、锁和网络连接
  • 有时,程序会永远保留这些资源,即使不再需要它们,这种现象称为内存泄漏
  • 因为每次创建和打开给定资源的新实例而不关闭现有资源时,可用内存都会减少

如何正确管理资源

  • 正确管理资源通常是一个棘手的问题
  • 它需要一个设置阶段和一个清理阶段
  • 后一个阶段需要执行一些清理操作,例如关闭文件、释放锁或关闭网络连接
  • 如果忘记执行这些清理操作,那么应用程序将使资源保持活动状态,这可能会损害宝贵的系统资源,例如内存和网络带宽

数据库连接数问题

  • 最常见的数据库连接数问题
  • 使用数据库时,可能会出现程序不断创建新连接而不释放或重用它们
  • 在这种情况下,数据库后端可以停止接受新连接
  • 这可能需要管理员登录并手动终止那些陈旧的连接以使数据库再次可用

写入文件问题

  • 将文本写入文件通常是一种缓冲操作
  • 这意味着对文件调用 .write() 不会立即导致将文本写入物理文件,而是写入临时缓冲区
  • 有时,当缓冲区未满而开发人员忘记调用 .close() 时,部分数据可能会永远丢失

with 的作用

常规说法

  • with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源
  • 比如文件使用后自动关闭/线程中锁的自动获取和释放等。

官方解释

  • 仅适用于执行上下文管理器定义的方法的代码块
  • 允许对普通的 try...except...finally  使用模式进行封装以方便地重用

一句话总结

使用 with as 语句操作上下文管理器(context manager),它能够帮助我们自动分配并且释放资源

什么是上下文管理器

详细教程

with as 的基本语法

with 表达式 [as target]:
代码块

执行顺序

  1. 调用表达式以获取上下文管理器
  2. 存储上下文管理器的 .__enter__() 和 .__exit__() 方法供以后使用
  3. 在上下文管理器上调用 .__enter__() 并将其返回值绑定到 target(如果有的话)
  4. 执行 with 代码块
  5. 当 with 代码块完成时,在上下文管理器上调用 .__exit__()

访问文件的代码演进

最基础的写法

# 1、打开文件
file = open("1.txt") # 2、读取文件
data = file.read() # 3、手动关闭文件
file.close()  

存在的问题

在第二步假设文件读取的时候发生异常,没有做任何处理,就不会执行第三步,导致程序可能会泄露文件描述符

使用 try...except...finally 优化

try:
# 打开文件、读取文件
f = open('xxx')
data = f.read()
except Exception as e:
# 捕获异常
pass
finally:
# 关闭文件
f.close()
  • 无论是否抛出异常,最后还是会关闭文件,解决上面提到的问题
  • 但新的问题在于,代码比较冗余,而且要手动关闭文件

使用 with 优化

with open("1.txt") as file:
data = file.read()
  • 作用和 try 写法一样
  • 优势:代码简洁,自动关闭文件,释放资源
  • with 代码块执行完后,会自动调用文件对象的 .close() 方法

支持多个上下文管理器

with open("input.txt") as in_file, open("output.txt", "w") as out_file:
# 从 input.txt 读取内容
# 转换内容
# 将转换后的内容写入output.txt
pass

等价写法

with open("input.txt") as in_file:
with open("output.txt", "w") as out_file:
pass

使用 pathlib.Path.open()

import pathlib

file_path = pathlib.Path("a.txt")
with file_path.open("w") as file:
file.write("Hello, World!")
  • 由于 pathlib 提供了一种优雅、直接和 Pythonic 的方式来操作文件系统路径
  • 因此应该考虑在 with 语句中使用 Path.open() 作为 Python 中的最佳实践

捕获异常的栗子

无论何时加载外部文件的程序都应检查可能存在的问题,例如文件丢失、读写访问等

import pathlib
import logging file_path = pathlib.Path("a.txt")
try:
with file_path.open("w") as file:
file.write("Hello, World!")
except OSError as error:
logging.error("Writing to file %s failed due to: %s", file_path, error)
  • 在 with as 外层添加 try ... except 用于捕获异常
  • 如果在执行 with 期间发生 OSError,则使用日志记录错误信息

遍历目录的栗子

import os

with os.scandir(".") as entries:
for entry in entries:
print(entry.name, "->", entry.stat().st_size, "bytes")
  • scandir() 会返回一个支持上下文管理协议的迭代器
  • .__exit__() 将调用 scandir.close() 关闭迭代器并释放获取的资源

输出结果

__init__.py -> 178 bytes
a.txt -> 13 bytes
1_上下文管理器.py -> 2168 bytes

高精度计算

Python - with 语句的更多相关文章

  1. Python —条件语句

    条件语句 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. 可以通过下图来简单了解条件语句的执行过程: Python程序语言指定任何非0和非空(null ...

  2. Python pass 语句使用示例

    Python pass 语句的使用方法示例.Python pass是空语句,pass语句什么也不做,一般作为占位符或者创建占位程序,是为了保持程序结构的完整性,pass语句不会执行任何操作,比如: P ...

  3. Python学习教程(learning Python)--1.2.1 Python输出语句print基本使用

    Python提供很多的内建(built-in)函数,使用者可以不用自己写代码就可以完成一个功能很强大的程序, 在Python里使用最多的(也许是)print函数主要用于用户输出信息. 基本用法:pri ...

  4. Python 条件语句

    Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. Python程序语言指定任何非0和非空(null)值为true,0 或者 null为false. Py ...

  5. python 循环语句 函数 模块

    python循环语句 while循环语法结构 当需要语句不断的重复执行时,可以使用while循环 while expression: while_suite 语句ehile_suite会被连续不断的循 ...

  6. jmeter数据库,charles抓包,Python循环语句

    jmeter数据库,charles抓包,Python循环语句 一.Jemeter数据库 添加jar包数据库 jemeter=>浏览 添加JDBC Connection Configuration ...

  7. Python import语句导入模块语法[转]

    Python import语句导入模块语法 社区推荐:掘金是国内最活跃的技术社区,我们每日有优质Python开发实例分享,海量python开源库推送.来掘金,和更多懂技术的小伙伴交流.   pytho ...

  8. python 基本语句

    python 基本语句 在使用python的变量前必须给它赋值,因为python变量没有默认值. 获取用户输入值 此时需要注意:input函数的返回值为文本或字符串. 一些简单的函数 乘方 绝对值 将 ...

  9. Python循环语句之break与continue的用法

    摘自原文章: http://www.jb51.net/article/73383.htm Python break 语句Python break语句,就像在C语言中,打破了最小封闭for或while循 ...

  10. python循环语句详细讲解

    想必大家都知道python循环语句吧,可以python循环语句有多种,比如for循环.while循环.if.else等等,   我们可以通过设置条件表达式永远不为 false 来实现无限循环,实例如下 ...

随机推荐

  1. NOIP 模拟 $29\; \rm 完全背包问题$

    题解 \(by\;zj\varphi\) 一道 \(\rm dp\) 题. 现将所有种类从小到大排序,然后判断,若最小的已经大于了 \(\rm l\),那么直接就是一个裸的完全背包,因为选的总数量有限 ...

  2. 盘点 HashMap 的实现原理及面试题

    1.请你谈谈 HashMap 的工作原理如果被问到 HashMap 相关的问题,它的工作原理都会被作为面试的开场白,这个时候先装作若有所思的样子冷静一下.首先 HashMap 是基于 hashing ...

  3. vue--三种组件中之间的传值

    参考网址:https://www.jianshu.com/p/46573a741c29 一.父子组件之间的传值----props/$emit 组件之间的传值,我们比较常用到的是props/$emit ...

  4. lock学习篇(上)

    why? 当我们使用线程的时候,效率最高的方式当然是异步,即各个线程同时运行,其间不相互依赖和等待. 但当不同的线程都需要访问某个资源的时候,就需要同步机制了,也就是说当对同一个资源进行读写的时候, ...

  5. Javascript - 异步操作和读取文件

    node.js读取文件 node.js内置了异步读取文件的模块,可以很方便地读取文件的数据.先创建三个txt文档,在根目录下创建一个readFile.js 输入以下代码,然后在vscode的终端中输入 ...

  6. freeswitch简介

    freeswitch简介 freeswitch是开源的,免费的. freeswitch是一款非常好用的电话软交换框架,支持跨平台,扩展性良好,配置灵活. freeswitch可以在很多平台上运行,包括 ...

  7. 🏆【Alibaba微服务技术系列】「Dubbo3.0技术专题」回顾Dubbo2.x的技术原理和功能实现及源码分析(温故而知新)

    RPC服务 什么叫RPC? RPC[Remote Procedure Call]是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范.它允许程序调用另一个地址空间(通常是共享网络的另 ...

  8. TDSQL MySQL版基本原理-水平分表 读写分离 弹性扩展 强同步

    TDSQL MySQL版(TDSQL for MySQL)是部署在腾讯云上的一种支持自动水平拆分.Shared Nothing 架构的分布式数据库.TDSQL MySQL版 即业务获取的是完整的逻辑库 ...

  9. LeetCode通关:连刷三十九道二叉树,刷疯了!

    分门别类刷算法,坚持,进步! 刷题路线参考:https://github.com/youngyangyang04/leetcode-master 大家好,我是拿输出博客来督促自己刷题的老三,这一节我们 ...

  10. Sentry-CLI 使用详解(2021 Sentry v21.8.x)

    内容源于:https://docs.sentry.io/platforms/javascript/guides/vue/ 系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创 ...