Python with 表达式详解

编程中,在我们使用系统资源的时候,如需打开一个文件用于读写,加锁确保线程安全,在使用完成后需要关闭该文件,释放我们所占用的资源。通常,我们可以将其封装在一个try...except...finally语句块中,这样能够确保在运行产生错误的情况我们也能释放相关资源。但每次都要记得手动关闭,着实麻烦。毕竟懒是是第一生产力,有没有更简便的写法?
答案是:有。Python提供了一个with表达式,只要将相关的代码块放入with表达式中,它便能起到一个类似try...except的作用,这使得我们不需要每次使用完成后再去手动关闭相关资源了。其使用语法为:

with_stmt ::=  "with" with_item ("," with_item)* ":" suite
with_item ::=  expression ["as" target]

例如:
with open('myfile.txt', 'w') as fd:
    # read or write here
    BLOCK1
    ...
    # other work

# outside with statement
# other work
BLOCK2
...

实际上,with表达式是将用户相关代码块封装在一个上下文管理器(context manager)中。所谓上下文管理器,通俗的讲,其实就是一个包含特定方法对__enter__, __exit__的对象,该方法对使得用户可以在进入相关代码块前设置好所需上下文环境,并在相关代码块退出后做一些善后工作,如释放资源,解锁等。
with的执行流程如下所示:

  1. 获取上下文管理器。例如上面代码块中的open('myfile.txt', 'w')会将文件自身返回;
  2. 上下文管理器的__enter__方法被调用;
  3. 第二步中的返回值被赋值到target,如果target存在的话;
  4. 执行with中的代码块,BLOCK1
  5. 上下文管理器的__exit__方法被调用。
  6. 判断代码块的退出原因,如果是因为一场退出,执行第7步,如果因为除了异常以外的原因(如正常退出),忽略第七步;
  7. 判断第5步中__exit__的返回值,如果是True,忽略异常继续执行后面代码,如果是False则抛出该异常,终止执行。
    上面几个步骤可以用伪代码表示如下:
context_manager = SomeKindOfManager()
target = context_manager.__enter__()
try:
    BLOCK1
finally:
    result = context_manager.__exit__()
    if reason is exception:
        if result:
            suppress exception
        else 
            raise exception

BLOCK2

上面提到的__exit__方法接收三个参数,分别是exception_type, exception_value, exception_traceback

下面,就用个小栗子作为结束吧。

class MyContextManager(object):                                                        

    def __enter__(self):
        return 'hello world'

    def __exit__(self, exc_type, exc_val, exc_traceback):
        print('Byebye')


with MyContextNanager() as msg:
    print(msg)

其结果为:

hello world
Byebye

最后说一句,Python定义了许多上下文管理器用于支持线程安全、关闭文件或其他资源等。详情请参阅contextlib


本文首发于个人公众号TensorBoy。如果你觉得内容还不错,欢迎分享并关注我的公众号TensorBoy,扫描下方二维码获取更多精彩原创内容!

公众号二维码

发布了45 篇原创文章 · 获赞 4 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/ZM_Yang/article/details/86649748
今日推荐