【Python】上下文管理协议__enter__和__exit__函数

部分程序中,可能事先要准备资源,事后做清理工作。 with方法就是python的非常酷的语句,安全可靠,方便。我们自己的类如何具备with的能力?必须拥有__enter__()函数和一个__exit__()函数,本章节介绍两个函数的能力。

        对于这种场景,一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。

一、with语句

1,文件读取操作,通常打开一个文件,然后读取文件内容,最后需要关闭文件,代码如下:

f = open("./demofile2",mode="r",encoding="UTF-8")
for content in f:
    print(content)
f.close()

这样的程序文件打开正常时没问题,但是存在2个问题

  •  可能忘记关闭文件句柄;
  •  文件读取数据发生异常,没有进行任何处理。

 

2,使用with语句如下:

with open("./demofile2",mode="r",encoding="UTF-8") as f:

    data = f.read()

# 离开with语句文件自动关闭
print(data)

3,with语句执行过程
        with操作很魔法,Python对with的处理还很聪明。基本思想是with所求值的对象必须有一个__enter__()方法,一个__exit__()方法。

        执行过程概述,with后面的语句被执行后,__enter__()函数被调用,_enter__()的返回值将被赋值给as后面的变量,后边详细说明_enter__()函数返回值问题。当with后面的代码块全部被执行完之后,将调用_enter__()返回对象的__exit__()方法。

函数及参数说明:

  • __enter__(self):当with开始运行的时候触发此方法的运行
  • __exit__(self, exc_type, exc_val, exc_tb):当with运行结束之后触发此方法的运行
  • exc_type如果抛出异常,这里获取异常的类型
  • exc_val如果抛出异常,这里显示异常内容
  • exc_tb如果抛出异常,这里显示所在位置

4,代码示例

class ConvertType(object):

    def __enter__(self):
        print("Entry with!")

        
    def __exit__(self,type,value,trace):
        print(f"type:{type}")
        print(f"value:{value}")
        print(f"trace:{trace}")
        print("Exit with!")
        
    def strToInt(self,targetString:str) -> int:
        return int(targetString)


with  ConvertType() as f:
    print(f)
    f.strToInt("1343f")

print("Done!")
    

4.1 执行结果

首先预测一下代码能否正常执行,尝试执行结果如下:

Entry with!
None
type:<class 'AttributeError'>
value:'NoneType' object has no attribute 'strToInt'
trace:<traceback object at 0x1110a6b80>
Exit with!
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[30], line 21
     19 with  ConvertType() as f:
     20     print(f)
---> 21     f.strToInt("1343f")
     23 print("Done!")

AttributeError: 'NoneType' object has no attribute 'strToInt'

报错分析:

发现print(f)打印为:None ,自然无法调用strToInt函数,也就是没有进入with...as代码块,原因如下:

with 语句执行时调用__enter__函数返回的对象成为f,这里__enter__函数没有return语句,默认返回None,因此f就是None

因此需要__enter__函数返回实例对象,修改代码如下:

class ConvertType(object):

    def __enter__(self):
        print("Entry with!")
        return self #新增一行返回值对象本身self
        
    def __exit__(self,type,value,trace):
        print(f"type:{type}")
        print(f"value:{value}")
        print(f"trace:{trace}")
        print("Exit with!")
        
    def strToInt(self,targetString:str) -> int:
        return int(targetString)


with  ConvertType() as f:
    print(f)
    f.strToInt("1343f")

print("Done!")

4.2 __enter__函数加返回值执行结果

Entry with!
<__main__.ConvertType object at 0x110fca000>
type:<class 'ValueError'>
value:invalid literal for int() with base 10: '1343f'
trace:<traceback object at 0x111070500>
Exit with!
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[31], line 21
     19 with  ConvertType() as f:
     20     print(f)
---> 21     f.strToInt("1343f")
     23 print("Done!")

Cell In[31], line 16, in ConvertType.strToInt(self, targetString)
     15 def strToInt(self,targetString:str) -> int:
---> 16     return int(targetString)

ValueError: invalid literal for int() with base 10: '1343f'

报错分析:

发现程序已经执行到了with...as代码块,在执行f.strToInt函数时报错了,原因是传入的参数“1343f”无法转化为int类型。另外我们还发现在with...as代码块执行失败后,最后一行代码print("Done!")没有被执行。

原因是__exit__函数没有返回值,在没有返回值的情况下,with...as代码块执行失败后,代码块程序会中断,即剩余代码块程序不会被执行,直接执行__exit__函数,__exit__函数无返回值的情况下会将错误暴露出来,如上执行结果。

那么给__exit__函数增加返回值“True”,修改代码:

class ConvertType(object):

    def __enter__(self):
        print("Entry with!")
        return self
        
    def __exit__(self,type,value,trace):
        print(f"type:{type}")
        print(f"value:{value}")
        print(f"trace:{trace}")
        print("Exit with!")
        return True #新增一行返回值True
        
    def strToInt(self,targetString:str) -> int:
        return int(targetString)


with  ConvertType() as f:
    print(f)
    f.strToInt("1343f")

print("Done!")

4.3 __exit__函数加返回值后执行结果

Entry with!
<__main__.ConvertType object at 0x1102c9c40>
type:<class 'ValueError'>
value:invalid literal for int() with base 10: '1343f'
trace:<traceback object at 0x1105d2180>
Exit with!
Done!

执行结果分析:

同样是参数“1343f”执行strToInt函数报错,但是错误信息被“吞掉”,没有暴露出来,而with...as语句块之外的剩余语句被执行,输出Done!

说明在__exit__函数返回True时,执行with...as代码块发生异常时会包装异常,执行会中断当前with...as语句块,然后执行执行__exit__函数,最后with语句以外的代码。

4.4 正常执行测试

给定一个数字类型的字符串进行测试,如“1343”,执行结果如下:

Entry with!
<__main__.ConvertType object at 0x1102ca450>
type:None
value:None
trace:None
Exit with!
Done!

说明在with...as语句块正常执行时,传入__exit__函数的参数type,value,trace都为None。

5,总结

发现python语言with语句有很大的魔力,类似我们编写try...except...finally结构的程序,但是with语句很优雅、便捷。在处理文件打开关闭、网络链接打开关闭、事务性程序的事务打开和关闭等都可以在__exit__函数中释放资源。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

笔记-----BFS宽度优先搜索

对于BFS&#xff1a;宽搜第一次搜到就是最小值&#xff0c;并且基于迭代&#xff0c;不会爆栈。 Flood Fill 模型 如果直译的话就是&#xff1a;洪水覆盖&#xff0c;意思就是像是从一个点一圈圈的往外扩散&#xff0c;如果遇见能够连通的就扩散&#xff0c;如果遇见无法联通的…

汽车4S集团数据分析

派可数据分析--汽车4S集团。 派可数据汽车4S集团数据分析概述。派可数据汽车4S集团分析主题全面涵盖行业内各板块业务分析&#xff0c;具体包括&#xff1a;保险业务分析、客户关系分析、汽车保养情况分析、售后维修主题分析、整车销售分析、整车库存分析、装具销售分析、配件…

原型和原型链--图解

https://juejin.cn/post/7255605810453217335 prototype是函数的属性&#xff08;一个对象&#xff09;&#xff0c;不是对象的属性&#xff0c;普通函数和构造函数的prototype属性是空对象&#xff5b;&#xff5d;&#xff08;其实有2个属性&#xff0c;一个是constructor&a…

账号安全基本措施2

sudo命令 sudo(superuser do)&#xff0c;允许系统管理员让普通用户执行一些或者全部的root命令的一个工具。 其配置在/etc/sudoers权。它允许系统管理员集中的管理用户的使用权限和使用的主机。属性必须为0440。 语法检查&#xff1a; 检查语法&#xff1a; 修改文件时&…

Excel中将单元格格式改成文本后,为何要双击数字才会改变?

将大批量的数值型数字转换成文本型数字&#xff0c;当然不能一个一个的去双击做转换了。以下说说有哪个可以将数值型数字转换成文本型数字的方法。 一、转换方法 方法1.数据分列功能 选中数据后&#xff0c;点击数据选项卡&#xff0c;分列&#xff0c; 分列向导的第一步和…

部署轻量级Gitea替代GitLab进行版本控制(一)

Gitea 是一款使用 Golang 编写的可自运营的代码管理工具。 Gitea Official Website gitea: Gitea的首要目标是创建一个极易安装&#xff0c;运行非常快速&#xff0c;安装和使用体验良好的自建 Git 服务。我们采用Go作为后端语言&#xff0c;这使我们只要生成一个可执行程序即…

ACL的基本配置

已经启用&#xff52;&#xff49;&#xff50;实现了全网可达。 这时我们要拒绝R1与R4的路由通信&#xff0c;做标准ACL过滤关注源IP需要尽量靠近目标。则在R4的物理接口G0/0/1的&#xff49;&#xff4e;接口上做&#xff0c;不能在R4的环回接口上做&#xff0c;因为ACL列表…

【Taro3踩坑日记】找不到sass的类型定义文件

问题截图如下&#xff1a;找不到sass的类型定义文件 解决办法&#xff1a; 1、npm i types/sass1.43.1 2、然后配置 TypeScript 编译选项&#xff1a;确保 TypeScript 编译器能够识别 Sass 文件&#xff0c;并正确处理它们。

小程序 前端如何用wx.request获取 access_token接口调用凭据

在微信小程序中&#xff0c;获取access_token通常是通过wx.request方法来实现的。以下是一个简单的示例代码&#xff1a; 1.获取小程序的appID 与 secret&#xff08;小程序密钥&#xff09; 登录之后,请点击左侧的"开发管理">点击"开发设置" 就可以找…

在Ubuntu 22.04上安装配置VNC实现可视化

前面安装的部分可以看我这篇文章 在Ubuntu 18.04上安装配置VNC实现Spinach测试可视化_ubuntu18开vnc-CSDN博客 命令差不多一样&#xff1a; sudo apt update sudo apt install xfce4 xfce4-goodies sudo apt install tightvncserver这个时候就可以启动server了 启动server&…

.net8系列-01手把手教你创建一个新的.net应用(.net7和.net8的不同点)以及三种方案进行接口调试

前提条件 如果没有安装VS2022.17.8 版本环境&#xff0c;请参考我的.net系列其他安装步骤文章来进行安装&#xff08;发布本文的时候另一篇文章正在审核无法放链接&#xff0c;等后续补充哦&#xff0c;也可以自己搜索我的博文哦~很齐全&#xff09; Windows版本.net环境搭建…

iOS -- 工厂设计模式

iOS -- 工厂设计模式 设计模式概念设计模式七大准则简单工厂模式优点缺点主要作用示例 工厂方法模式优点缺点主要作用&#xff1a; 抽象工厂方法缺点主要作用&#xff1a;文件分类 设计模式概念 所谓设计模式&#xff08;Design pattern&#xff09; 是解决软件开发某些特定问…

nginx installed inLinux

yum install nginx [rootmufeng ~]# yum install nginx CentOS系列&#xff1a;【Linux】CentOS7操作系统安装nginx实战&#xff08;多种方法&#xff0c;超详细&#xff09; ———————————————— 版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC …

Maven通过flatten-maven-plugin插件实现多模块版本统一管理

正文 起因是公司开始推代码版本管理的相关制度&#xff0c;而开发过程中经常使用多模块构建项目&#xff0c;每次做版本管理时都需要对每个模块及子模块下的pom文件中parent.version和模块下依赖中的version进行修改&#xff0c;改的地方非常多&#xff0c;且非常容易漏。为此…

Pytorch 学习路程

目录 下载Pytorch 入门尝试 几种常见的Tensor Scalar Vector Matrix AutoGrad机制 线性回归尝试 使用hub模块 Pytorch是重要的人工智能深度学习框架。既然已经点进来&#xff0c;我们就详细的介绍一下啥是Pytorch PyTorch 希望将其代替 Numpy 来利用 GPUs 的威力&…

深度学习pytorch实战4---猴逗病识别·

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营](https://mp.weixin.qq.com/s/0dvHCaOoFnW8SCp3JpzKxg) 中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊](https://mtyjkh.blog.csdn.net/)** 引言 1.复习上周并反思 K同学针对大家近…

【数据结构】图论(图的储存方式,图的遍历算法DFS和BFS、图的遍历算法的应用、图的连通性问题)

目录 图论一、 图的基本概念和术语二、图的存储结构1. 数组(邻接矩阵)存储表示无向图的数组(邻接矩阵)存储表示有向图的数组(邻接矩阵)存储表示 邻接表存储表示有向图的十字链表存储表示无向图的邻接多重表存储表示 三、图的遍历算法图的遍历——深度优先搜索&#xff08;DFS&a…

FPGA_verilog语法整理

FPGA_verilog语法整理 verilog的逻辑值 verilog的常数表达 位宽中指定常数的宽度&#xff08;表示成二进制数的位数&#xff09;&#xff0c;单引号加表示该常数为几进制的底数符号。 二进制底数符号为b&#xff0c;八进制为 o&#xff0c;十进制为d&#xff0c;十六进制为 h…

递归、搜索与回溯算法——穷举vs暴搜vs深搜

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享递归、搜索与回溯算法关于穷举vs暴搜vs深搜的专题 如果有不足的或者错误的请您指出! 目录 1.全排列1.1解析1.2题解 2.子集2.1解析2.1.1解法12.1.2解法1代码2.1.3解法22.1.4解法…

vscode微博发布案例

样例: CSS代码: * {margin: 0;padding: 0; }ul{list-style: none; }.w {width: 900px;margin: 0 auto; }.controls textarea {width: 878px;height: 100px;resize: none;border-radius: 10px;outline: none;padding-left: 20px;padding-top: 10px;font-size: 18px; }.controls…
最新文章