上下文管理

本文主要讲解:

  1. Python上下文管理的定义与作用;
  2. 上下文管理器的使用;
  3. 自定义上下文管理器;
  4. 上下文管理器装饰器/python提供的上下文管理的模块;

 

一、Python上下文管理的定义与作用

        上下文管理器是Python2.5之后才出现的概念。上下文管理器规定了某个对象的使用范围,当进入或者离开了使用范围,都会有相应的一些调用,比如代码块开始时执行一些准备,代码块结束时结束一些操作。它更多的是用于资源的分配和释放上,即在开始时分配资源,结束时释放一些资源。比如在执行数据库查询时要建立连接,查询结束后要释放连接;写文件时要先打开文件,写结束后,要关闭文件等等。还有,就是资源的加锁和解锁,比如在使用多线程时,可能会用到加锁和解锁。

二、上下文管理器的使用

上下文协同管理(__enter__和 __exit__)

# class Foo:
#     def __init__(self,name):
#         self.name = name
#     def __enter__(self):
#         print('执行enter',self)
#         return self
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         print('执行exit')
#         print(exc_type)
#         print(exc_val)
#         print(exc_tb)
#
# with Foo('a.txt') as f:   # 相当于f = obj.__enter__() ##  with时触发enter
#     print('------')
#     print('=====')
# print('000000')    ### 上面的代码块执行完毕时触发exit
## 没有异常时,with 下的代码块运行完毕,自动触发exit,exc_type, exc_val, exc_tb三个参数均为None

# class Foo:
#     def __init__(self,name):
#         self.name = name
#     def __enter__(self):
#         print('执行enter',self)
#         return self
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         print('执行exit')
#         print(exc_type)
#         print(exc_val)
#         print(exc_tb)
#
# with Foo('a.txt') as f:   # 相当于f = obj.__enter__() ##  with时触发enter
#     print('------')
#     print(sdhf)   ## 异常
#     print('=====')
# print('000000')
## 有异常时,到异常那句代码,直接触发、__exit__,此时三个参数为
# exc_type  <class 'NameError'>;
# exc_val name 'sdhf' is not defined
###  exc_tb <traceback object at 0x0000000002203148>

class Foo:
    def __init__(self,name):
        self.name = name
    def __enter__(self):
        print('执行enter',self)
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('执行exit')
        print(exc_type)
        print(exc_val)
        print(exc_tb)
        return True

with Foo('a.txt') as f:   # 相当于f = obj.__enter__() ##  with时触发enter
    print('------')
    print(sdhf)   ## 异常
    print('=====')
print('000000')
## 有异常,但是exit返回值为True时,会吞掉异常,遇到异常那句代码,执行exit,然后开始执行with外面的代码

# 好处
#1.使用with语句的目的就是把代码放在with中执行,with结束后,自动完成清理工作,无需手动干预
#2.在需要管理一些资源,比如文件,网络连接,和锁的编程环境中,可以在__exit__中定制自动释放资源的机制。

 三 contextlib模块

Python中还有一个contextlib模块提供一些简便的上下文管理器功能。

CLOSING()方法

如果说with语句块在退出时会自动调用”__exit__()”方法的话,那用了”contextlib.closing()”的with语句块则在退出时会自动调用”close()”方法。看一下示例:

 

程序运行后,会打印出

Open Resource
Close Resource

说明Resource类创建的对象被赋给了as关键字后面的变量r,而with语句块退出时,自动调用了”r.close()”方法。

CONTEXTMANAGER装饰器

“@contextlib.contextmanager”是一个装饰器,由它修饰的方法会有两部分构成,中间由yield关键字分开。由此方法创建的上下文管理器,在代码块执行前会先执行yield上面的语句;在代码块执行后会再执行yield下面的语句。看个例子比较容易明白:

 

 

这个”timeit()”方法实现了一个计时器,它会计算由他生成的with语句块执行时间。可以看出,yield上面的语句就如同之间介绍过的”__enter__()”方法,而yield下面的语句就如同”__exit__()”方法。而yield部分就是with语句块中的代码。如果yield后面带参数的话,我们就可以用as关键字赋值给后面的变量,比如上例:

 

 

需要注意的是,”@contextlib.contextmanager”不像之前介绍的”__exit__()”方法,遇到异常也会执行。也就是with语句块抛出异常的话,yield后面的代码将不会被执行。所以,必要时你需要对yield语句使用”try-finally”。

posted @ 2018-08-28 21:43  神秘嘉宾7m  阅读(157)  评论(0编辑  收藏  举报