美文网首页Python
Python的上下文管理器

Python的上下文管理器

作者: 李白开水 | 来源:发表于2020-07-19 10:41 被阅读0次

先来看一小段代码:

try:
    print("code started")
    raise KeyError
except KeyError as e:
    print("key error")

运行结果:

code started
key error

try先打印,然后发生异常,捕获异常,打印。

如果抛的是另外一个异常:

try:
    print("code started")
    raise IndexError
except KeyError as e:
    print("key error")

就会出错:

code started
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-12-d67568d8860d> in <module>
      1 try:
      2     print("code started")
----> 3     raise IndexError
      4 except KeyError as e:
      5     print("key error")

IndexError:

如果是预测不到的异常,在python中使用else:

try:
    print("code started")
    # raise IndexError
except KeyError as e:
    print("key error")
else:
        print("other error")

运行结果:

code started
other error

把raise IndexError注释掉是因为,如果不注释掉,那么运行到raise IndexError就会直接抛出异常,不会走下面的了。

在try中还有一种用法finally,finally就是不管前面的try和else的有没有运行,都会运行finally中的代码:

try:
    print("code started")
    # raise IndexError
except KeyError as e:
    print("key error")
else:
        print("other error")
finally:
        print("finally")

运行:

code started
other error
finally

所以,如果我们在try中打开一个文件,使用完这个文件后就需要关闭这个文件:

try:
        f_read = open("hellp.txt")
        .....
        f_read .close()

但是如果在关闭文件之前发生了异常,那么就执行不到关闭文件这一行。

所以在这种情况下,要在捕获异常的代码后面加上close:

try:
    f_read = open("hellp.txt")
        .....
        f_read .close()
except KeyError as e:
    print("key error")
        f_read .close()
else:
        print("other error")
        f_read .close()

如果捕获异常还有很多其他的error,还要写很多close:

try:
    f_read = open("hellp.txt")
        .....
        f_read .close()
except KeyError as e:
    print("key error")
        f_read .close()
except IndexError as e:
    print("index error")
        f_read .close()
else:
        print("other error")
        f_read .close()

如果使用finally的话,不管有没有异常都会进入finally,所以就可以直接把close写在finally:

try:
    f_read = open("hellp.txt")
        .....
        f_read .close()
except KeyError as e:
    print("key error")
except IndexError as e:
    print("index error")
else:
        print("other error")
finally:
        f_read .close()

再深入理解一下执行过程:

修改一下代码:

def exe_try():
    try:
        print("code started")
        raise KeyError
        return 1
    except KeyError as e:
        print("key error")
        return 2
    except IndexError as e:
        print("index error")
        return 3
    else:
        print("other error")
        return 4
    finally:
        print("finally")
        return 5

看一下执行结果:

In [16]: exe_try()
code started
key error
finally
Out[16]: 5

执行顺序:
try print之后发生KeyError异常,这时候不return1,进入except KeyError,但是并没有return 2 是因为,return语句在try——except——finally中的用法是,如果finally有return语句,就return finally中的语句,如果没有,再返回之前调用地方的return语句。

所以如果把finally中的return语句注释掉,那他就会返回2:

In [20]: exe_try()
code started
key error
finally
Out[20]: 2

Python中的with语句简化了try和finally,就是上下文管理器。

上下文管理器协议主要实现了两个魔法函数:__enter____exit__

实现了上下文管理器协议的类,就可以被with调用。

也就是说,只要这个类实现了__enter____exit__,那么这个类就可以叫做上下文管理器。

例如:

class Sample:
    def __enter__(self):
        print("using enter")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("using exit")

    def dosomething(self):
        print("doing something")

使用with调用Sample类:

In [22]: with Sample() as s:
    ...:     s.dosomething()
    ...:
using enter
doing something
using exit

在这个过程中,enter返回什么,with就会给Sample什么。

在with中并没有调用魔法函数,但是with还是自动调用了enter,离开with的时候又调用了exit。

也就是enter时获取资源,exit时释放资源。

还可以更简化:

python提供了一个contextlib包,这个包中有一个装饰器@contextlib.contextmanager,这个装饰器可以把函数变为一个上下文管理器,这个装饰器修饰的函数必须是一个生成器,也就是用yield返回。

用一小段代码模拟打开文件:

import contextlib

@contextlib.contextmanager
def file_open(file_name):
    print("file open")
    yield {}
    print("file end")

使用with调用一下:

In [24]: with file_open("hello.txt") as f:
    ...:     print("processing")
    ...:
file open
processing
file end

可以看到执行顺序是,先打开文件,然后执行with中的语句,最后执行关闭文件的print,所以在yield之前的语句相当于enter魔法函数,yield之后的相当于exit魔法函数。

也可以这么使用:

from contextlib import contextmanager

@contextmanager
def file_open(file_name):
    print("file open")
    yield {}
    print("file end")

相关文章

  • Python上下文管理器和with块

    python中with语句用起来很方便,那这后边的原理就是python中的上下文管理器。 1.什么是上下文管理器 ...

  • 算法面试 - 问题记录

    python上下文管理器,装饰器? (1)上下文管理器知乎链接:https://zhuanlan.zhihu.co...

  • python 上下文管理器

    一、什么是上下文管理器? 上下文管理器类型是python的内置类型之一,上下文管理器的定义:允许用户自定义类来定义...

  • python上下文管理

    什么是上下文管理 上下文:context的直译, 指的是代码执行过程中的前后状态上下文管理器:python上下文管...

  • Python上下文管理器

    Context Manager 文档翻译 Python with语句支持上下文管理器定义的运行时上下文概念(run...

  • Tornado源码分析(二)异步上下文管理(StackConte

    异步异常与上下文 在Python黑魔法---上下文管理器最后关于上下文的使用,提到了tornado的处理方式。本篇...

  • python 基础深入

    contextlib 上下文管理器 创建上下文管理实际就是创建一个类,添加enter和exit方法 Python...

  • Python上下文管理器

    上下文管理器 概念:实现了上下文协议的对象即为上下文管理器。 上下文管理器的协议: __enter__进入的方法_...

  • python中上下文管理器

    什么是上下文管理器? 代码的环境就是上下文,实现了上下文管理器协议的类产生的实例就是上下文管理器对象。在类中声名e...

  • Python:上下文管理器 与 contextlib 的用法解析

    1. 上下文管理器 1.1. 引言 在 python 语言中经常会使用 with ... as ... 语句,...

网友评论

    本文标题:Python的上下文管理器

    本文链接:https://www.haomeiwen.com/subject/xbhqkktx.html