python上下文管理器

1.what AND demo

我们希望把一些操作放到一个代码块中,这样在代码块中执行时就可以保持在某种运行状态,而当离开该代码块时就执行另一个操作,结束当前状态;所以,简单来说,上下文管理器的目的就是规定对象的使用范围,如果超出范围就采取“处理”。

with 语句内置上下文管理工具。

with open("test/test.txt","w") as f:
  f.write("hello")

不使用上下文管理工具:

f = open("hl.txt", "w")
print(f.closed)  #运行到这里,会打印出False,因为没有关闭
f.write("Hello,context manager!")
f.close()
print(f.closed)  #这里才会打印出True,表示文件关闭

如果这段代码根本执行不到f.close()这一句,就出现问题,这样就永远执行不到f.close()这一句,文件就永远不会被关闭。

可以用try…finally语句。

2.how自定义一个上下文管理器

上下文管理协议(Context Management Protocol):包含方法 __enter__() 和 __exit__(),支持该协议的对象要实现这两个方法。
上下文管理器(Context Manager):支持上下文管理协议的对象,这种对象实现了__enter__() 和 __exit__() 方法。上下文管理器定义执行 with 语句时要建立的运行时上下文,负责执行 with 语句块上下文中的进入与退出操作。通常使用 with 语句调用上下文管理器,也可以通过直接调用其方法来使用。
运行时上下文(runtime context):由上下文管理器创建,通过上下文管理器的 __enter__() 和__exit__() 方法实现,
__enter__() 方法在语句体执行之前进入运行时上下文,
__exit__() 在语句体执行完后从运行时上下文退出。with 语句支持运行时上下文这一概念。
上下文表达式(Context Expression):with 语句中跟在关键字 with 之后的表达式,该表达式要返回一个上下文管理器对象。

class MyMananger:
    # __enter__ 返回的对象会被with语句中as后的变量接受
    def __enter__(self):
        print('connect to resource')
        return self

    def __exit__(self, exc_type, exc_value, tb):
        print('close resource conection')

    def query(self):
        print('query data')
with MyManager() as r:
    r.query()

结果:

connect to resource
query data
close resource conection

3.contextlib中的装饰器contextmanager

demo1:

from contextlib import contextmanager
class Mydoit:
    def doit(self):
        print('just do it')

@contextmanager
def make_contextmanager():
    print('start to connect')
    yield Mydoit()
    print('end connect')
    pass

被装饰器装饰的函数分为三部分: 
with语句中的代码块执行前执行函数中yield之前代码 
yield返回的内容复制给as之后的变量 
with代码块执行完毕后执行函数中yield之后的代码

with Mydoit() as r:
     r.doit()

结果是:

start to connect
just do it
end connect

 demo2:

#通过一个 yield 分为2个部分.
#yield 前的代码 相当于 __enter__ , yield 后的代码相当于 __exit__
#而 yiled 产出的值 相当于  as 的变量上.

import contextlib
 
#装饰一下 
@contextlib.contextmanager
def open_file(filepath):
 
    #相当于 __enter__
    print("准备打开")
    fileObject = open(filepath,'r')
    print("打开结束 , 准备yield")
 
    # fileObject 将赋值 给  as 后的变量
    yield fileObject
 
 
    # 下面的代码相当于 __exit__
    print("准备close")
    fileObject.close()
    print("close完成")
 
 
 
with open_file("D:dex.txt") as fd:
    print("with 块进入了")
    time.sleep(3)
    print("完成操作")

demo3:

from contextlib import contextmanager
 
@contextmanager
def example():
    l = [1,2,3,4]
    print('start')
    try:
        # raise Exception('test')
        yield l
    finally:
        print('end')
        
with example() as msg:
    try:
        for i in msg:
            print(i)
    except:
        print(e.message)
            
start
1
2
3
4
end
原文地址:https://www.cnblogs.com/wqbin/p/10693602.html