美文网首页
python中的上下文管理器和with

python中的上下文管理器和with

作者: 伍只蚊 | 来源:发表于2017-07-19 18:05 被阅读35次

    之前只知道with...as语句可以作用于一些资源文件的操作,比如filelike对象,可以使它打开后,即使异常也自动关闭,还有线程锁的获取与释放。
    其实with的作用对象不止这些,只要是上下文管理器对象,都能应用with语句

    什么是上下文管理器?

    我们用with打开一个文件对象,with语句其实实现了 打开文件,执行代码块,关闭文件的流程。上下文管理器其实就是 在执行代码块 之前做一些准备,做完之后在做一些善后的工作,这就完成了对代码块中的这一部分的上下文的管理。

    怎么实现上下文管理器?

    1. 自定义类实现两个魔法方法:enter,exit
    class Son(object):
        def __init__(self,name):
            self.name = name
    
        def __enter__(self):
            print('%s诞生了'%self.name)
        def __exit__(self, exc_type, exc_val, exc_tb):
            
                print('顺利诞生')
    
    
    s = Son('wu')
    with s as g:
        print(s.name)
        
        
        结果:
        wu诞生了
        wu
        顺利诞生
        
    

    enter方法中执行的工作就是进入代码块前干的准备工作,他的返回值可以用as接收,而exit中干的就是代码块执行完后的工作。
    若在执行代码块中发生异常,exit方法仍会执行,并且可以捕获到异常信息,具体详情我还没搞明白。

    2.通过@contextmanager将一个生成器变为上下文管理器
    @contextmanager是contextlib模块下的一个装饰器,他接收的函数必须是生成器

    import contextlib
    
    
    @contextlib.contextmanager
    def get_file(filename):
        print('正在打开文件')
        f = open(filename,'r',encoding='utf8')  #代码块执行前的准备工作
        yield f
        print('正在关闭文件')
        f.close()#执行后的善后工作
    
    with get_file('test.py') as g:
        print('正在读取文件')
        print(g.read())
    
    结果:
    正在打开文件
    正在读取文件
    #coding=utf8
    文件内容
    正在关闭文件
    

    在被装饰的生成器函数中,yield之前的部分就是 代码块执行前准备的内容,yield之后的就是代码块执行后的善后处理,yield返回的值可以用 as 赋予一个变量,在代码块中使用。
    通过contextmanager装饰的生成器返回的是上下文管理器,这样就可以用with语句了。

    3.通过context.closing类把一个对象变为上下文管理器对象

    import contextlib
    from urllib.request import urlopen
    
    with contextlib.closing(urlopen('http://wwww.baidu.com')) as f:
        print(f.readline())
    

    这是closing类的源码,其实就是传入对象初始化一个上下文管理器类对像,在exit中实现调用close(),在enter中返回原来的对象,用as可以获取

    class closing(AbstractContextManager):
      
        def __init__(self, thing):
            self.thing = thing
        def __enter__(self):
            return self.thing
        def __exit__(self, *exc_info):
            self.thing.close()
    

    总结一下:上下文管理器总是配合with语句一起使用,作用是在with语句块的执行前和执行后完成指定功能。
    创建上下文管理器的方法有三种:

    1. 自定义类,实现enter,和exit方法
    2. 通过 @contextmanager将一个生成器变为上下文管理器,yield前后分别在代码块前后执行
    3. 利用context.closing类把一个对象变为上下文管理器对象,传入对象参数,在exit中调用对象的close方法

    相关文章

      网友评论

          本文标题:python中的上下文管理器和with

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