为了账号安全,请及时绑定邮箱和手机立即绑定

Python 技巧探究:上下文管理器和with语句

标签:
Python


webp

一:前言

Python 里面的 with 语句是被认为是晦涩难懂的特征之一,但是当你窥视它的内部你就会发现这里面并没有什么魔法。事实上它可以帮助我们写一些整洁和可读性高的代码。

那么 with 语句适合用于哪方面呢?它可以帮助我们简化一些常见的资源管理模式,允许它们被提取和重用。

二:案例探究

还是来看一个最常见的打开文件的例子吧!

with open('name.txt','w') as f:
    f.write('hello world')

使用 with 语句去打开文件的好处在于,不管文件是否正常打开,最后文件都会被正常的关闭。实际上前面的代码可以翻译为下面的方式:

f = open('name.txt','w')try:
    f.write('hello world')finally:
    f.clouse()

当然这样写看起来确实挺废话的,但是其实 try...finally 语法是很重要的。
如果不用这个语法,可能会这样写:

f = open('name.txt','w')
f.write('hello world')
f.clouse()

这样的写法看起来挺正常的,但是实际上它保证不了文件的正常关闭,如果文件没有正常关闭就会出现很多问题,所以使用 with 语句是很有必要的,它帮助我们正确的获取和释放资源。

with 语句的另一个好用的例子是在 Python 的标准库里的 threading.Lock

lock = threading.Lock# 普通的方式:lock.acquir()try:    # do somethingfinally:
    lock.release()# 更好的方式:with lock:    # do something

通过这两个例子可以看到:使用 with 语句允许我们抽象更多的资源处理逻辑,取代每次显式的使用 try...finally 语句,方便我们写代码。舒服了哦!
with 语句可以使得处理系统资源的代码可读性更高,它帮助我们避免 bug 或者忘记释放资源。

三:让自己的项目支持with语句

现在其实觉得 open()threading.Lock 没啥特殊或者魔法的。他们实际上都是可以使用 with 语句的。 我们也可以在类里面通过实现上下门管理器提供一些功能。

啥是上下文管理器( context manager) ?它是一个简单的接口,最基本的是我们写的这个类要实现 双下划线方法:__enter____exit__ ,Python 会在资源管理中适当的调用这两个方法。
让我们看看它是怎么实现 open() 上下文管理的:

class ManagedFile:
     def __init__(self, name)
           self.name = name     def __enter__(self):           self.file = open(self.name, 'w')           return self.file     def __exit__(self, exc_type, exc_val, exc_tb):           if self.file:
               self.file.close()

这个 ManagedFile 类就实现了上下文管理器协议,那么就支持使用 with 语句,就像使用最开始的 open() 的例子那样:

with ManagedFile('name.txt') as f:
    f.write('hello Python')

当使用 with 语句进入上下文管理器时 Python 调用 __enter__方法,同时将获取到资源,当离开上下文管理器的时候 Python 调用 __exit__ 方法去释放资源。
像上面这样写一个基于上下文管理器的累不是在Python中支持 with 语句的唯一方法。 Python 标准库中的 contextlib 模块提供了一些基于上下文管理器的协议。

例如我们可以使用 contextlib.contextmanager 装饰一个基于生成器的工厂函数,这样就可以使用 with 语句,来看看例子吧:

from contextlib import contextmanager@contextmanagerdef manager_file(name):
      try:
           f = open(self.name, 'w')           yield f      finally:
              f.close()

这样使用:

with manager_file('name.txt') as f:
    f.write('hello python')

在这个例子中 manager_file() 是一个生成器,在开始的时候获取到资源,然后暂时性的停止程序 yiled 这个资源给调用者。当调用者离开了上下文,这个生成器就会继续执行后续的代码,所以最后资源可以被释放给系统。

上面一个基于类的和基于生成器的方法去使用 with 语句是等价的,选一个可读性好的就行。
这里有一个问题就是,基于装饰器的实现方法要求开发者懂一些例如装饰器、生成器这样高级的 Python 语法概念。不过真的想学习 Python 这些高级语法也是要学习的。



作者:rieuse
链接:https://www.jianshu.com/p/b3be7b5b00f5


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消