简单认识下with和上下文管理器

news2024/10/6 4:02:51

with

对于系统资源如文件、数据库连接、socket,应用程序打开这些资源并执行完业务逻辑之后,必须关闭(断开)该资源。系统允许打开的最大文件数量是有限的,如果我们打开文件后没有及时关闭,极端情况下会出现:Too many open files 错误。对于数据库来说,如果没有关闭的连接数量过多,也会出现:Can not connect to MySQL server Too many connections 错误。

我们最开始最基础使用的是以下方式来关闭资源

def m1():
    f = open("output.txt", "w")
    f.write("python之禅")
    f.close()
    print("查看文件是否已关闭:",f.closed)

m1()
    
# 结果
# 查看文件是否已关闭: True

在这里插入图片描述

在能够确保程序稳定安全运行的情况下,这样运行没有问题。一旦代码量增多,可能会忘记使用close去关闭文件,而且最大的问题是,如果程序运行在中间代码如f.write(“python之禅”)时出错,那后面就不再运行f.close(),文件也就无法正常关闭。针对第二个问题,我们采用了try…exception…finally…的方式:

def m1():
    try:
        f = open("output.txt", "w")
        f.write("hello world!")
        print("查看文件是否已关闭:", f.closed)
    except Exception as e:
        print(e)
    finally:
        f.close()
        print("查看文件是否已关闭:",f.closed)
        
m1()

# 结果
# 查看文件是否已关闭: False
# 查看文件是否已关闭: True

在这里插入图片描述

我们都知道,不管程序在运行try语句中出现了什么问题,都会运行finally中的语句。现在虽然解决了第二个问题,那有没有什么办法能够解决第一个问题呢?这个时候就要提及with了,我们先看看下面一段代码:

def m1():
    with open("output.txt", "w") as f:
        f.write("python之禅")
    print("查看文件是否已关闭:",f.closed)

m1()

# 结果
# 查看文件是否已关闭: True

在这里插入图片描述

上面的代码中,我们只是使用了一个with,并没有看到使用了close(),代码运行完之后,文件就关闭了。实际上它并不是没有运行到close(),而是在with内部语句运行完之后,自动调用了文件类中的__exit__()魔法方法,在这个方法中实现了f.close(),整块代码运行过程如下:

1、运行m1(),调用m1变量指向的代码块

2、运行with open(“output.txt”, “w”) as f,使用关键字with,开启上下文管理,f = open(“output.txt”, “w”),即自动调用文件类中的__enter__()魔法方法,得到self.f

3、运行f.write(“python之禅”)

4、跳出with前,自动运行__exit__()魔法函数,实现self.f.close()关闭文件

5、打印出文件关闭状态

看完上面的流程,想必对with和两个魔法方法、上下文管理器还是一头雾水。那我们就再了解下什么是上下文管理器,with、enter()、exit()和上下文的关系。

上下文管理器

所谓上下文管理器,就是实现了__enter__()和__exit__()两个魔法方法的对象,上下文管理器可以使用with关键字。在遇到with关键字的时候,会自动去调用运行需要处理的对象中的__enter__()魔法方法,在运行完with中的语句时,会自动去调用运行处理完的对象的中的__exit__()魔法方法,前后呼应。

上面的例子中,文件之所以能够使用with,并在使用后自动关闭文件,就是因为文件对象实现了__enter__()魔法方法和__exit__()魔法方法。下面我们来证实下:

class MyFile:
    def __init__(self, filename, mode):
        self.filename =filename
        self.mode = mode

    def __enter__(self):
        print("entering.......")
        self.f = open(self.filename, self.mode)
        return self.f

    def __exit__(self, *args):
        self.f.close()
        print("exit......")

with MyFile("output.txt", "w") as f:
    print("writing")
    f.write("hello, world!")
    
# 结果
# entering.......
# writing
# exit......

在这里插入图片描述

contextManager

除了通过__enter__()和__exit__()方法实现上下文管理器,还有一种更加简便的方式,就是装饰器+yield

from contextlib import contextmanager


@contextmanager
def my_test(filename, mode):
    f = open(filename, mode)
    yield f
    f.close()

with my_test("output.txt", "w") as f:
    f.write("hello, dear!")

在这里插入图片描述

当执行f = my_test(“output.txt”, “w”)时,会执行mytest()中的 f = open(filename, mode)语句,遇到yield时,返回f并停止运行。当运行完with中的代码时,猜测是调用了next()方法继续运行mytest上次中断后的代码,即f.close()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/419093.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

21天学会C++:Day2----命名空间的那些事儿

CSDN的uu们,大家好。这里是C入门的第二讲。 座右铭:前路坎坷,披荆斩棘,扶摇直上。 博客主页: 姬如祎 收录专栏:C专题 目录 1. 为什么要有命名空间 2. 命名空间的定义 3. 访问命名空间域中成员的三种方…

基于Java+SpringBoot+vue的人职匹配推荐系统设计与实现【源码(完整源码请私聊)+论文+演示视频+包运行成功】

博主介绍:专注于Java技术领域和毕业项目实战 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇🏻 不然下次找不到哟 Java项目精品实战案例(300套) 目录 一、效果演示 二、…

virtualbox如何配网

配网搞了一天!!! 百度到的所有教程都是垃圾!! 就没有一个写全的!!写明白怎么配的!!! 我自己来!!!不会配的看我&#xf…

浅析 Queue 和 Deque

终于开始了 LeetCode 的练习,看到 102. 二叉树的层序遍历 有种解法利用到了队列,想着挨个看看基础队列中的方法,便有了这篇文章。 基于 Java 对 Queue 以及 Deque(double ended queue) 实现进行学习介绍,JD…

Vue之代码传送(teleport)

代码传送是啥 在Vue中,代码传送就是将某部分的代码从Vue的template标签下传送到指定的地方,这个地方通常是body标签下。在使用Vue编写界面时,我们都是在html的Body中写一个div,然后指定一个id,然后在Vue的实例中的tem…

2023春招offer收割机,阿里架构师耗时半月写的《Java面试手册》

程序猿在世人眼里已经成为高薪、为人忠诚的代名词。 然而,小编要说的是,不是所有的程序员工资都是一样的。 世人所不知的是同为程序猿,薪资的差别还是很大的。 众所周知,目前互联网行业是众多行业中薪资待遇最好的,包…

Java语法理论和面经杂疑篇《九. 网络编程》

目录 1. 网络编程概述 1.1 软件架构 1.2 网络基础 2. 网络通信要素 2.1 如何实现网络中的主机互相通信 2.2 通信要素一:IP地址和域名 2.2.1 IP地址 2.2.2 域名 2.3 通信要素二:端口号 2.4 通信要素三:网络通信协议 2. 谈传输层协议…

时间序列教程 四、自回归和移动平均模型

一、本节目标 了解自相关函数(ACF)。 了解部分自相关函数(PACF)。 了解自回归和移动平均模型是如何工作的。 使用Python来拟合自相关模型。 二、ACF和PACF 1、自相关函数(ACF) 测量信号与自身延迟数据的相关性。 它用于发现信号中的重复模式,例如周期性信号的存…

Spring相关概念

Spring家族 官网:Spring | Home,从官网我们可以大概了解到: Spring能做什么:用以开发web、微服务以及分布式系统等,光这三块就已经占了JavaEE开发 的九成多。Spring并不是单一的一个技术,而是一个大家族,可以从官网的…

.NET基础加强第七课--文件流

序列化 JSON序列化 例子 using Nancy.Json; Person p1 new Person(); p1.Name “zs”; // json 序列化 JavaScriptSerializer javaScriptSerializer new JavaScriptSerializer(); string json javaScriptSerializer.Serialize(p1); Console.WriteLine(json); Console.…

linux-创建子进程的过程与原理(fork讲解)

我们知道,子进程可以被命令行创建,被fork函数创建,但是子进程创建了什么呢,是完全拷贝父进程函数?还是继承父进程数据呢? 首先我们要知道,进程的构成:进程内核数据结构可运行程序载…

二维差分【算法推导,图文讲解清晰】

798. 差分矩阵 - AcWing题库 算法推导 二维差分相对一维差分会复杂一点,而且还要结合二维前缀和的一些细节处理 A、B数组角色问题 在差分思想中,构造并不是那么重要,而是其中A、B数组的角色。 我们假想存在一个数组B,输入的A…

论文阅读《NeRF-Supervised Deep Stereo》

论文地址:https://arxiv.org/pdf/2303.17603.pdf 源码地址:https://nerfstereo.github.io/ 概述 针对深度估计的标签数据难以获取,自监督方法在病态(遮挡、非朗伯面)区域的表现差,跨域泛化能力弱的问题&…

【jvm系列-06】深入理解对象的实例化、内存布局和访问定位

JVM系列整体栏目 内容链接地址【一】初识虚拟机与java虚拟机https://blog.csdn.net/zhenghuishengq/article/details/129544460【二】jvm的类加载子系统以及jclasslib的基本使用https://blog.csdn.net/zhenghuishengq/article/details/129610963【三】运行时私有区域之虚拟机栈…

Vue——组件基础

目录 定义一个组件​ 使用组件​ 传递 props​ 监听事件​ 通过插槽来分配内容​ 动态组件​ DOM 模板解析注意事项​ 大小写区分​ 闭合标签​ 元素位置限制​ 组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。在实际应…

Learning to summarize from human feedback导读(1)

总结: (1)生成摘要等模型,虽然有评估方法,但是人类总结的质量依旧难以相比 总结: (1)在各种NLP任务中,大规模语言模型的预训练以及取得了很高的性能 (2&am…

PHP快速入门09-正则相关,附一定要学会的20个高频使用案例

文章目录前言一、正则表达式介绍二、正则高频案例20个2.1 检查字符串是否以字母开头2.2 检查字符串是否以数字开头2.3 检查字符串是否包含特定字符2.4 检查字符串是否以特定字符结尾2.5 检查字符串是否为纯数字2.6 检查字符串是否为纯字母2.7 检查字符串是否为有效的电子邮件地…

Bean对象的作用域和生命周期

文章目录:一.Bean的作用域 (1)Bean作用域的含义 (2)Bean的6种作用域 二.Bean的生命周期(1)开辟内存空间 (2) 属性注入 (3)初始化 (4)使用Bean (…

【CSDN|每日一练】运输石油

目录 运行结果题目描述输入描述:输出描述:示例代码结语运行结果 题目描述 某石油公司需要向A、B两地运输石油。 两地的需求量不同,而一辆车只能装载一定量的石油。 经过计算A地需要a辆车,B地需要b辆车运输才能满足需求。 现在一共有n辆车分布在各地,每辆车前往A、B两地…

HFSS一些使用技巧总结

1. 快捷键: CTRLH,隐藏选择的object、face 字母E,选择edge(线) alt左键双击九个区域,切换9个不同的视角(与789组合使用) 2. 复制: 这样的复制好处在于:复制完的物体相…