python中的上下文管理器和with

之前只知道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)