python中的with关键字原理详解

对于系统资源如文件、数据库连接、socket 而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭(释放)该资源。
在代码中经常会看见 with open(file) as f 对文件进行操作,其中 with 关键字到底有什么用处呢?让我们一起来看看如何正确关闭一个文件。

1.普通版

def fun1():
    f = open("test.txt", "w")
    f.write("hello python")
    f.close()

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

2.进阶版

def fun2():
    try:
        f = open("test.txt", "w")
        f.write("hello python")
    except Exception as e:
        print(e)
    finally:
        f.close()

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

3.高级版

def fun3():
    with open("test.txt", "w") as f:
        f.write("hello python")

一种更加简洁、优雅的方式就是用with关键字。open方法的返回值赋值给变量f,当离开with代码块的时候,系统会自动调用 f.close() 方法,with 的作用和使用 try/finally 语句是一样的。那么它的实现原理是什么?在讲with的原理前要涉及到另外一个概念,就是上下文管理器(Context Manager)。
什么是上下文?
上下文在不同的地方表示不同的含义,要感性理解。在编程中 context 上下文其实说白了就是环境。
例如 一个 APP 应用,在切换界面的时候,要保存你是在哪个屏幕跳过来的等等信息,以便你点击返回的时候能正确跳回,如果不存肯定就无法正确跳回了。
再比如线程、协程进行任务切换时,程序怎么能知道切换到另一个任务,是从头开始执行还是从中间呢?其上下文就起到作用,就是任务本身会对其环境进行保存,做到哪里了,做了多少,各种状态都会标识记录,从而形成了上下文环境,因此在切换时根据每个任务的上下文环境,继续执行,从而达到多任务。

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

4.用类还原with的实现原理

class Fun4(object):
    def __init__(self, file_name, mode):
        self.file_name = file_name
        self.mode = mode
    def __enter__(self):
        self.f = open(self.file_name, self.mode)
        return self.f
    def __exit__(self,*args):
        self.f.close()
with Fun4("test.txt", "w") as f:
    f.write("hello python")
"""
首先Test4("1.txt", "w")初始化实例对象,
然后with会寻找类中是否有__enter__和__exit__,
如果有则调用__enter__函数,
最后__enter__()方法返回资源对象,这里就是你将要打开
的那个文件对象,__exit__()方法处理一些清除工作。
"""

5.使用contextmanager装饰器,实现with功能

from contextlib import contextmanager
"""
Python还提供了一个contextmanager的装饰器,更进一步简化
了上下文管理器的实现方式。通过yield将函数分割成两部分,yield之前的
语句在__enter__方法中执行,yield之后的语句在__exit__方法中执行。
紧跟在yield后面的值是函数的返回值。
"""
@contextmanager
def fun5(path, mode):
    f = open(path, mode)
    yield f
    f.close()
with fun5("test.txt", "w") as f:
    f.write("hello python")

总结:
Python 提供了 with 语法用于简化资源操作的后续清除操作,是 try/finally 的替代方法,实现原理建立在上下文管理器之上。此外,Python 还提供了一个 contextmanager 装饰器,更进一步简化上下管理器的实现方式。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值