在python只要实现了__enter__、__exit__方法,即支持上下文管理器协议。上下文管理器就是支持上下文管理器协议的对象,它是为了with而生。当with语句在开始运行时,会在上下文管理器对象上调用__enter__方法,运行结束后会调用__exit__方法( 必须在这个对象的类中同时声明__enter__和__exit__方法 )。
class Open:
def __init__(self, name):
self.name = name
def __enter__(self):
print('出现with语句,__enter__方法被触发,有返回值则赋值给as后声明的变量')
def __exit__(self, exc_type, exc_val, exc_tb):
print('with执行结束执行我------')
print(exc_type) # 异常类型
print(exc_val) # 异常值
print(exc_tb) # 异常追溯信息
with Open('a.text') as f:
print('执行-------')
raise AttributeError('不知道为什么要报错')如果__exit__方法返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行
模拟open
class Open:
def __init__(self, filepath, mode='r', encoding='utf-8'):
self.filepath = filepath
self.mode = mode
self.encoding = encoding
def __enter__(self):
print('出现with语句,__enter__方法被触发,有返回值则赋值给as后声明的变量')
self.f = open(self.filepath, self.mode, encoding=self.encoding)
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
print('with执行结束执行我------')
print(exc_type) # 异常类型
print(exc_val) # 异常值
print(exc_tb) # 异常追溯信息
return True # 如果没有返回true with发生异常。后面代码则不会执行
with Open('a.text', 'w') as f:
print('执行-------')
f.write('hello world')
#################################################
出现with语句,enter方法被触发,有返回值则赋值给as后声明的变量
执行-------
with执行结束执行我------
None
None
None模拟mysql连接
import pymysql
class DB:
def __init__(self, username, password, host='127.0.0.1', port=3306, db='', charset='utf8'):
self.name = username
self.passwd = password
self.host = host
self.port = port
self.db = db
self.charset = charset
def __enter__(self):
# 创建数据库连接
self.conn = pymysql.connect(user=self.name, passwd=self.passwd, host=self.host, port=self.port, db=self.db, charset=self.charset)
# 创建游标
self.dbcur = self.conn.cursor()
# 返回游标
return self.dbcur
def __exit__(self, exc_type, exc_val, exc_tb):
# 提交事务
self.conn.commit()
# 关闭游标
self.dbcur.close()
# 关闭连接
self.conn.close()
with DB('root', '123456', db='mysql') as db:
db.execute('select host,user from user')
print(db)
for i in db:
print(i)
######################################################
<pymysql.cursors.Cursor object at 0x0000000002DAC160>
('127.0.0.1', 'root')
('::1', 'root')
('localhost', '')
('localhost', 'root')总结
- with DB -----》触发DB.__enter__
- as db -----》DB.__enter__ 的返回值
- 没有异常的情况下,整个代码块运行完毕后去触发__exit__,它的三个参数都为None
- 有异常的情况下,从异常出现的位置直接触发__exit__
- 如果__exit__的返回值为True,代表忽略了异常
- 如果__exit__的返回值为False,代表主动抛出异常
- __exit__运行完毕,代表with语句已全部执行结束
with的好处
- 将代码块放在with中执行,with结束后,自动完成清理工作,无需手动操作
- 在需要管理资源如文件、网络、锁的编程中可以在__exit__中定制自动释放资源的机制





Comments | NOTHING