python进阶学习(五)上下文管理器和with语句

目录

  • with语句
  • 上下文管理器
  • @contextmanager
  • 其他应用


with语句

with语句想必大家都使用过,用它来读写文件十分方便,而且它会自动帮助我们关闭文件

with open('x_train', 'rb') as f:
    x_train = pickle.load(f)

当然with肯定不止这么一个作用,其实with语句可以当做是简化版的try\finally语句,即一段代码运行完毕之后,无论这段代码是否出现问题,最终都要执行某些个操作,例如释放资源等等。

上下文管理器

定义一个上下文管理器类其实很简单,只要实现它的__enter__和__exit__方法即可

假设现在有一个上下文管理叫做ContextManager,那么使用它的语句就是

with ContextManager as cm:
	pass

其中as是可选的,它的值就是__enter__方法的返回值,打开文件时必须要有一个变量来接受文件对象,不过也有很多情况不需要返回具体的值

而__exit__中写的内容就是类似于finally语句的内容,__exit__中的代码将在with语句结束或者with语句中代码运行出问题时或者return时执行,且必定会执行

例如我们假装定义一个数据库连接上下文管理器

class DataBaseManager:

    def __enter__(self):
        manager = "MySQL database connection"
        print("database connection success!")
        return manager

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("database connection finish!")


with DataBaseManager() as manager:
    print(manager+" execute operation")

运行结果为:

database connection success!
MySQL database connection execute operation
database connection finish!

__enter__中除了self没有别的参数

在__exit__中exc_type,exc_val和exc_tb这三个参数,如果没有异常均为None,否则会被赋予异常的类,异常实例以及tracback对象

在__exit__中处理异常时,如果最后不返回True,那么会使异常继续向上冒泡

@contextmanager

@contextmanager这个装饰器可以把一个生成器函数变成一个上下文管理器,算是上面方式的简便写法,这个装饰器在模块contextlib中,当然这个模块也有其他上下文管理器的辅助函数

我们把上面的例子改写成使用@contextmanager的形式,输出结果是一样的

@contextlib.contextmanager
def DataBaseManager():
    manager = "MySQL database connection"
    print("database connection success!")
    yield manager
    print("database connection finish!")


with DataBaseManager() as manager:
    print(manager+" execute operation")

函数中yield语句相当于原本__enter__中的return

在yield上面的语句相当于写在__enter__中的语句

在yield下面的语句相当于写在__exit__中的语句

其他应用

上下文管理其他的应用地方还有很多

线程锁,配置上下文环境等等

放个python functools里面的源码,虚拟可重入锁

class RLock:
    'Dummy reentrant lock for builds without threads'
    def __enter__(self): pass
    def __exit__(self, exctype, excinst, exctb): pass

上一篇:python进阶学习(四)装饰器与闭包

你可能感兴趣的:(python,#,进阶学习,python,进阶学习,读书笔记,上下文管理器)