Python程序设计 上下文管理器

上下文管理器

如果你有阅读源码的习惯,可能会看到一些优秀的代码经常出现带有 “with” 关键字的语句,它通常用在什么场景呢?

对于系统资源如文件、数据库连接、socket 而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭(断开)该资源。

比如 Python 程序打开一个文件,往文件中写内容,写完之后,就要关闭该文件,否则会出现什么情况呢?极端情况下会出现 "Too many open files" 的错误,因为系统允许你打开的最大文件数量是有限的。

同样,对于数据库,如果连接数过多而没有及时关闭的话,就可能会出现 "Can not connect to MySQL server Too many connections",因为数据库连接是一种非常昂贵的资源,不可能无限制的被创建。

来看看如何正确关闭一个文件。

简单使用

普通版:
f = open("output.txt", "w")
f.write("python")
f.close()

这样写有一个潜在的问题,如果在调用 write 的过程中,出现了异常进而导致后续代码无法继续执行,close 方法无法被正常调用,因此资源就会一直被该程序占用者释放。那么该如何改进代码呢?

进阶版:
f = open("output.txt", "w")
try:f.write("python")
except IOError:print("oops error")
finally:f.close()

改良版本的程序是对可能发生异常的代码处进行 try 捕获,使用 try/finally 语句,该语句表示如果在 try 代码块中程序出现了异常,后续代码就不再执行,而直接跳转到 except 代码块。而无论如何,finally 块的代码最终都会被执行。因此,只要把 close 放在 finally 代码中,文件就一定会关闭。

高级版:
with open("output.txt", "r") as f:f.write("Python")

一种更加简洁、优雅的方式就是用 with 关键字。open 方法的返回值赋值给变量 f,当离开 with 代码块的时候,系统会自动调用 f.close() 方法, with 的作用和使用 try/finally 语句是一样的。那么它的实现原理是什么?在讲 with 的原理前要涉及到另外一个概念,就是上下文管理器(Context Manager)。

上下文管理器

什么是上下文(context)

上下文在不同的地方表示不同的含义,要感性理解。context其实说白了,和文章的上下文是一个意思,在通俗一点,我觉得叫环境更好。....

看这些都是上下文的典型例子,理解成环境就可以,(而且上下文虽然叫上下文,但是程序里面一般都只有上文而已,只是叫的好听叫上下文。。进程中断在操作系统中是有上有下的,不过不这个高深的问题就不要深究了。。。)

任何实现了 __enter__()和 __exit__()方法的对象都可称之为上下文管理器,上下文管理器对象可以使用 with 关键字。显然,文件(file)对象也实现了上下文管理器。

那么文件对象是如何实现这两个方法的呢?我们可以模拟实现一个自己的文件类,让该类实现 __enter__() 和 __exit__() 方法。

class File():def __init__(self, filename, mode):self.filename = filenameself.mode = modedef __enter__(self):print("===进入上下文管理器===")self.f = open(self.filename, self.mode)return self.fdef __exit__(self, *args):print("===退出上下文管理器===")self.f.close()def operate(self):print('===在上下文管理器里面操作===')

 __enter__() 方法返回资源对象,这里就是你将要打开的那个文件对象,__exit__() 方法处理一些清除工作。

这就是上下文管理协议的一个强大之处,异常可以在__exit__ 进行捕获并由你自己决定如何处理,是抛出呢还是在这里就解决了。在__exit__ 里返回 True(没有return 就默认为 return False),就相当于告诉 Python解释器,这个异常我们已经捕获了,不需要再往外抛了。

在 写__exit__ 函数时,需要注意的事,它必须要有这三个参数:

  • exc_type:异常类型
  • exc_val:异常值
  • exc_tb:异常的错误栈信息

当主逻辑代码没有报异常时,这三个参数将都为 None。

因为 File 类实现了上下文管理器,现在就可以使用 with 语句了。

with File('out.txt', 'w') as f:print("writing")f.write('hello, python')

这样,你就无需显示地调用 close 方法了,由系统自动去调用,哪怕中间遇到异常 close 方法也会被调用。

在我看来,这和 Python 崇尚的优雅风格有关。

  1. 可以以一种更加优雅的方式,操作(创建/获取/释放)资源,如文件操作、数据库连接;
  2. 可以以一种更加优雅的方式,处理异常;

另一种实现

Python 还提供了一个 contextmanager 的装饰器,更进一步简化了上下文管理器的实现方式。通过 yield 将函数分割成两部分,yield 之前的语句在 __enter__ 方法中执行,yield 之后的语句在 __exit__ 方法中执行。紧跟在 yield 后面的值是函数的返回值。

from contextlib import contextmanager@contextmanager
def my_open(path, mode):f = open(path, mode)yield ff.close()

调用

with my_open('out.txt', 'w') as f:f.write("hello , the simplest context manager")

总结

总结起来,使用上下文管理器有三个好处:

  1. 提高代码的复用率
  2. 提高代码的优雅度
  3. 提高代码的可读性

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

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

相关文章

中科方德服务器操作系统安装zabbix5.0

原文链接:中科方德服务器操作系统安装zabbix5.0 Hello,大家好啊!接着我们上一次的讨论,今天我要为大家介绍如何在已经安装好的中科方德服务器操作系统基础上,安装和配置Zabbix 5.0。Zabbix是一个开源的监控软件工具&am…

LeetCode-416. 分割等和子集【数组 动态规划】

LeetCode-416. 分割等和子集【数组 动态规划】 题目描述:解题思路一:01背包问题,动规五部曲解题思路二:0解题思路三:0 题目描述: 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分…

Vue异步组件,深入解析

基本用法​ 在大型项目中,我们可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件。Vue 提供了defineAsyncComponent方法来实现此功能: import { defineAsyncComponent } from vueconst AsyncComp defineAsyncComponent(() >…

贪心算法|738.单调递增的数字

力扣题目链接 class Solution { public:int monotoneIncreasingDigits(int N) {string strNum to_string(N);// flag用来标记赋值9从哪里开始// 设置为这个默认值,为了防止第二个for循环在flag没有被赋值的情况下执行int flag strNum.size();for (int i strNum.…

Open3D生成规则点云(二)

一、代码 Python import open3d as o3d import numpy as np# 定义正方体的参数 def create_square(x1=0, y1=0, z1=0, side_length=1, resolution=20):vertices = []for i in range(resolution):for j in range(resolution):for k in range(resolution):x = x1 + i * side_le…

2020 年 9 月青少年软编等考 C 语言一级真题解析

目录 T1. 输出整数思路分析 T2. 新冠疫情死亡率思路分析 T3. 有一门课不及格的学生T4. 整数的个数思路分析 T5. 金币 T1. 输出整数 输入四个整数,把输入的第三、第四个整数输出。 时间限制:1 s 内存限制:64 MB 输入 只有一行,共…

python爬虫 - 下载图片

文章目录 1、下载图片示例1:使用 .urlretrieve() 函数2、下载图片示例2 - 使用 open/write 函数3、下载图片示例33.1 使用 open/write 下载3.2 使用 urlretrieve下载 爬虫的本质:模拟对应的App,浏览器访问对应的地址获取到数据 1、下载图片示…

考虑预同步的虚拟同步机T型三电平逆变器并离网MATLAB仿真模型

微❤关注“电气仔推送”获得资料(专享优惠) 模型简介 三相 T 型三电平逆变器电路如图所示,逆变器主回路由三个单相 T 型逆变器组成。 直流侧输入电压为 UPV,直流侧中点电位 O 设为零电位,交流侧输出侧是三相三线制连…

高防虚拟主机的重要性

在当今数字化时代,网络安全已经成为企业和个人必须面对的重要议题。随着网络攻击手段的不断升级和多样化,传统的虚拟主机已经难以满足日益增长的安全需求。在这样的背景下,高防虚拟主机应运而生,成为保护网站安全、抵御网络攻击的…

4.双向循环链表的模拟实现

1.双向链表的实现 1.1双向链表节点的结构声明 typedef int LTDataType;typedef struct ListNode {struct ListNode* prev; // 指向该节点的前一个节点struct ListNode* next; // 指向该节点的后一个节点LTDataType data; // 该节点中存储的数据 }LTNode; // 将这…

Linux内核errno-base.h源码分析

上次写过一个博客,主要关于内核错误相关的源码分析(链接),最近突然发现上次的分析不完善,因此本次完善相关分析。 Linux内核中经常见到一些返回值,如-12,比如下面是我遇到过的一个截图&#xff…

【Java面试题】MySQL上篇(索引)

文章目录 索引1.索引的分类?2.B树和B树的区别?2.1B树2.2B树 3.为什么使用索引会加快查询?4.创建索引的注意点?5.索引在哪些情况下会失效?6.聚簇索引和非聚簇索引的区别?7.回表查询是什么?8.什么…

阿里云租用服务器GPU配置报价单_1年_一个月_1小时价格表

阿里云GPU服务器租用价格表包括包年包月价格、一个小时收费以及学生GPU服务器租用费用,阿里云GPU计算卡包括NVIDIA V100计算卡、T4计算卡、A10计算卡和A100计算卡,GPU云服务器gn6i可享受3折优惠,阿里云服务器网aliyunfuwuqi.com分享阿里云GPU…

机器学习—概述(一)

什么是机器学习 数据 模型 预测 从历史数据当中获得规律?这些历史数据是怎么的格式? 数据集构成 特征值+目标值 机器学习算法分类 监督学习 目标值:类别一分类问题 k-近邻算法、贝叶斯分类、决策树与随机森林、逻辑回归目标值:连续型的数据一回归问题 线性回…

电脑磁盘空间不足?学会这几招,轻松释放磁盘空间

随着科技的飞速发展,电脑已成为我们日常生活中不可或缺的一部分。无论是工作、学习还是娱乐,我们都需要依赖电脑来完成。然而,随着电脑使用时间的增长,磁盘空间不足的问题也逐渐浮现。当磁盘空间不足时,不仅会影响电脑…

2023年金融贷款骗局套路之一

源地址:2023年金融贷款骗局套路之一_预防网贷套路_计算机技术网 随着无卡消费的日夜流行,三年疫情出现,钱难寻,难找的尴尬境地,贷款骗局也出现不少。今天我们讲讲最近很流行的贷款骗局之一中的一种贷款骗局。 在平常…

AIoT人工智能物联网之AI 实战

1. jetson-inference 入门 jetson-inference是官方推出的体验套件,提供了三种最常见的AI应用于计算机视觉的类型,imagenet用于 图像辨识 ( Image Recognition )、detectNet用于对象辨识 ( Object Detection )、segNet用于语义分割 可以先使用windows下载 jetson-inference(因…

第40篇:有限状态机<三>

Q:本期我们介绍有限状态机的应用之一:摩尔状态机“1101”序列检测器。 A:当检测到序列1101时,状态机输出为1。定义s_0为初始状态(即没有检测到1输入的状态),摩尔状态机的输出仅取决于现态&…

基于SpringBoot+Vue的个性化推荐电商平台(源码+文档+部署+讲解)

一.系统概述 随着网络科技的不断发展以及人们经济水平的逐步提高,网络技术如今已成为人们生活中不可缺少的一部分,而信息管理系统是通过计算机技术,针对用户需求开发与设计,该技术尤其在各行业领域发挥了巨大的作用,有…

数学建模-Matlab中randperm函数及其双重进阶版

1.randperm函数的用法 (1)这种用法就是参数只有一个数字,代表的含义就是随机排列之后打印输出; 我们举例的数字是4,就会把1到4这4个数字随机打乱之后随机输出,每次运行结果都不一样 所有可能的情况是n的…