个人总结:
1、一个类只要实现了__enter__()方法和__exit__()方法,那么这样的类就称为上下文管理器。
就像一个类中实现了__iter__()方法和__next__()方法那么这个类就是一个迭代器,道理类似。
同理生成器是一种特殊的迭代器,特殊就在它里面有yeild,一个函数里面有yield那么它就是个迭代器对象了,而一个函数用@contextmanager装饰器装饰后并且其内部有yield它就是一个上下文管理器对象了。yield之前的代码相当于enter方法,yield之后的代码相当于exit函数,yield后的返回值相当于enter的返回值。
2、with:后面如果是个上下文管理器对象,那就会自动调用其中的enter方法,如果enter方法有返回值则用as xx:的方式接收, xx指向该返回值,没有返回值或不需要接收可以不写 as xx:。当whit:后面的缩进代码块执行结束后则会自动调用其中的exit方法,不管缩进块中的代码有没有产生异常。
举个demo:
#!/usr/bin/python3
2 # -*- coding:utf-8 -*-
3
4 # context_manager.py
5 import time
6 from contextlib import contextmanager
7
8
9 class MyClass():
10 """一个类只要实现了__enter__方法和__exit__方法,这样的类就称为上下文管理
器"""
11
12 def __init__(self,file_name,mode):
13 self.file_name = file_name
14 self.mode = mode
15
16 def __enter__(self):
17 print("enter method is running")
18 self.file = open(self.file_name,self.mode)
19 return self.file
20
21 def __exit__(self,*args,**kwargs): # exit 方法有四个参数,具体没研究过
22 print("exit method is running")
23 self.file.write("999999999999")
24 self.file.close()
25 #self.f.write("111111111111") # 整上这个会报错,I/O operation on
# closed file
26
27
28 @contextmanager
29 def my_cm(file_name,mode):
30 f = open(file_name,mode)
31 yield f
32 f.close()
33 print("f was closed")
34
35
36 if __name__ == "__main__":
37 # 方式一、MyClass类中的enter方法返回值file用as f方式给到f,不接收返回可不
写
38 # 1.with后面的对象如果是个上下文管理器就会自动调用其中的enter方法
39 # 2.with:缩进代码块执行完后会自动调用exit方法,不管缩进代码有没有产生异常
40
41 #a.用as f接收enter的返回值
42 #with MyClass("test.txt","a") as f:
43 #f.write("hahhhha")
45 #b.不需要接收返回值
46 with MyClass("test1.txt","a"):
47 for i in range(5):
48 print(i)
49 time.sleep(2)
50
51 print("方式一运行结束!")
52
53
55 # 方式二、通过装饰器的方式来实现
56 with my_cm("test3.txt","a") as f:
57 f.write("您好!有意思")
58 print("方式二运行结束!")
运行结果:
enter method is running
0
1
2
3
4
exit method is running
方式一运行结束!
f was closed
方式二运行结束!