概念:实现了上下文协议的对象即为上下文管理器
上下文协议:__enter__、__exit__
作用:用于资源的获取和释放
open()函数的实现内部就是使用了以上两种方法
任何对象,只要正确实现了上下文管理,就可以用于with语句。
实现上下文管理是通过__enter__和__exit__这两个方法实现的,
也可以通过@contextmanager和closing函数实现
含有__enter__和__exit__方法的对象就是上下文管理器
class Foo(object):
def __init__(self):
print('实例化一个对象')
def __enter__(self):
print('进入')
def __exit__(self, exc_type, exc_val, exc_tb):
print('退出')
obj = Foo()
with obj:
print('正在执行')
上面代码执行结果为:
实例化一个对象
进入
正在执行
退出
with 上下文管理器:
语句体
当with遇到上下文管理器,就会在执行语句体之前,先执行上下文管理器的__enter__方法,然后再执行语句体,执行完语句体后,最后执行__exit__方法
出现异常时,如果 exit 返回 False(默认不写返回值时,即为False),则会重新抛出异常,让with 之外的语句逻辑来处理异常,这也是通用做法;如果返回 True,则忽略异常,不再对异常进行处理
class Foo(object):
def __init__(self):
print('实例化一个对象')
def __enter__(self):
print('进入')
def __exit__(self, exc_type, exc_val, exc_tb):
print('退出')
# return True
obj = Foo()
with obj:
raise ImportError
print('正在执行')
调用上下文管理器的 enter 方法时;如果使用了 as 子句,则将 enter() 方法的返回值赋值给 as 子句中的目标
class Foo(object):
def __init__(self):
print('实例化一个对象')
def __enter__(self):
print('进入')
# return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('退出')
with Foo() as obj:
print(obj,type(obj))
print('正在执行')
with 上下文管理器 as target:
代码语句体
with后面必须跟一个上下文管理器,如果使用了as,则是把上下文管理器的 enter() 方法的返回值赋值给 target,target 可以是单个变量,或者由“()”括起来的元组(不能是仅仅由“,”分隔的变量列表,必须加“()”)
使用了 with 语句,不管在处理文件过程中是否发生异常,都能保证 with 语句执行完毕后已经关闭了打开的文件句柄
with open("/tmp/foo.txt") as file:
data = file.read()
比较try语句起来,使用 with 语句可以减少编码量。已经加入对上下文管理协议支持的还有模块 threading、decimal 等
进一步简化上下文管理 ----- Python 提供了一个 contextmanager 装饰器
from contextlib import contextmanager
class MyResource:
def query(self):
print('query data')
@contextmanager
def make_myresource():
print('start to connect')
yield MyResource()
print('end connect')
pass
被装饰器装饰的函数分为三部分:
with语句中的代码块执行前执行函数中yield之前代码
yield返回的内容复制给as之后的变量
with代码块执行完毕后执行函数中yield之后的代码
比如下方代码:
with make_myresource() as r:
r.query()
执行结果是
start to connect
query data
end connect
数据库操作
from pymysql import *
class Database(object):
def __init__(self,name,password):
# 创建self.conn连接
self.conn = connect(host='localhost',port=3306,database=str(name),user='tiger',password=str(password),charset='utf8')
# 获得self.cursor对象
self.cursor = self.conn.cursor()
def __enter__(self):
return self.cursor # 返回self.cursor对象
def __exit__(self, exc_type, exc_val, exc_tb):
self.cursor.close() # 关闭self.cursor对象
self.conn.close() # 关闭self.conn连接
with Database('zzj_01','mysql') as db:
db.execute(""" select * from students; """) # 执行sql语句
content = db.fetchall() # 获取数据
#遍历获取到的数据,打印每一条数据
for info in content:
print(info)