Python深入学习之上下文管理器

作者:junjie 时间:2023-03-27 19:09:43 

上下文管理器(context manager)是Python2.5开始支持的一种语法,用于规定某个对象的使用范围。一旦进入或者离开该使用范围,会有特殊操作被调用 (比如为对象分配或者释放内存)。它的语法形式是with...as...

关闭文件

我们会进行这样的操作:打开文件,读写,关闭文件。程序员经常会忘记关闭文件。上下文管理器可以在不需要文件的时候,自动关闭文件。

下面我们看一下两段程序:


# without context manager
f = open("new.txt", "w")
print(f.closed)               # whether the file is open
f.write("Hello World!")
f.close()
print(f.closed)


以及:


# with context manager
with open("new.txt", "w") as f:
    print(f.closed)
    f.write("Hello World!")
print(f.closed)


两段程序实际上执行的是相同的操作。我们的第二段程序就使用了上下文管理器 (with...as...)。上下文管理器有隶属于它的程序块。当隶属的程序块执行结束的时候(也就是不再缩进),上下文管理器自动关闭了文件 (我们通过f.closed来查询文件是否关闭)。我们相当于使用缩进规定了文件对象f的使用范围。

上面的上下文管理器基于f对象的__exit__()特殊方法(还记得我们如何利用特殊方法来实现各种语法?参看特殊方法与多范式)。当我们使用上下文管理器的语法时,我们实际上要求Python在进入程序块之前调用对象的__enter__()方法,在结束程序块的时候调用__exit__()方法。对于文件对象f来说,它定义了__enter__()和__exit__()方法(可以通过dir(f)看到)。在f的__exit__()方法中,有self.close()语句。所以在使用上下文管理器时,我们就不用明文关闭f文件了。

自定义

任何定义了__enter__()和__exit__()方法的对象都可以用于上下文管理器。文件对象f是内置对象,所以f自动带有这两个特殊方法,不需要自定义。

下面,我们自定义用于上下文管理器的对象,就是下面的myvow:


# customized object

class VOW(object):
    def __init__(self, text):
        self.text = text
    def __enter__(self):
        self.text = "I say: " + self.text    # add prefix
        return self                          # note: return an object
    def __exit__(self,exc_type,exc_value,traceback):
        self.text = self.text + "!"          # add suffix


with VOW("I'm fine") as myvow:
    print(myvow.text)

print(myvow.text)

我们的运行结果如下:


I say: I'm fine
I say: I'm fine!


我们可以看到,在进入上下文和离开上下文时,对象的text属性发生了改变(最初的text属性是"I'm fine")。

__enter__()返回一个对象。上下文管理器会使用这一对象作为as所指的变量,也就是myvow。在__enter__()中,我们为myvow.text增加了前缀 ("I say: ")。在__exit__()中,我们为myvow.text增加了后缀("!")。

注意: __exit__()中有四个参数。当程序块中出现异常(exception),__exit__()的参数中exc_type, exc_value, traceback用于描述异常。我们可以根据这三个参数进行相应的处理。如果正常运行结束,这三个参数都是None。在我们的程序中,我们并没有用到这一特性。

总结:

通过上下文管理器,我们控制对象在程序不同区间的特性。上下文管理器(with EXPR as VAR)大致相当于如下流程:


# with EXPR as VAR:

VAR = EXPR
VAR = VAR.__enter__()
try:
    BLOCK
finally:
    VAR.__exit__()

由于上下文管理器带来的便利,它是一个值得使用的工具。

标签:Python,上下文管理器
0
投稿

猜你喜欢

  • js判断文件是否为utf-8编码的方法

    2024-04-22 13:06:51
  • Python类型转换的魔术方法详解

    2022-04-16 12:49:06
  • 在ASP中使用SQL语句之5:开始执行

    2007-08-11 12:36:00
  • 解决mysql报错:Data source rejected establishment of connection, message from server: \\"Too many connectio

    2024-01-13 05:53:57
  • Golang 中 omitempty的作用

    2024-04-25 15:13:03
  • pyqt5实现绘制ui,列表窗口,滚动窗口显示图片的方法

    2023-03-22 16:52:56
  • C#如何实现对sql server数据库的增删改查

    2024-01-18 06:49:09
  • vue实现验证码倒计时按钮

    2024-04-09 10:49:05
  • MySQL分组查询Group By实现原理详解

    2024-01-14 12:00:15
  • 安装完成后如何找回SQL Server实例安装时的序列号

    2024-01-16 02:07:27
  • python tensorflow学习之识别单张图片的实现的示例

    2023-06-30 21:11:32
  • python实现批量修改文件名代码

    2023-05-04 14:44:41
  • PHP设计模式(八)装饰器模式Decorator实例详解【结构型】

    2023-11-24 05:59:31
  • Python基于SMTP协议实现发送邮件功能详解

    2022-07-17 00:31:00
  • Python办公自动化SFTP详解

    2021-10-11 13:04:27
  • 如何在Django项目中引入静态文件

    2021-10-09 11:24:52
  • sqlserver数据库主键的生成方式小结(sqlserver,mysql)

    2024-01-20 07:49:23
  • Django学习之文件上传与下载

    2023-09-24 18:42:23
  • python3+PyQt5 使用三种不同的简便项窗口部件显示数据的方法

    2021-10-25 12:14:57
  • 深入Golang中的sync.Pool详解

    2024-02-02 05:31:27
  • asp之家 网络编程 m.aspxhome.com