Python 上下文管理器
概要: Python中实现上下文管理器的3种方式
创建时间: 2022.10.20 21:15:13
更新时间: 2022.10.20 22:21:54
需求示例
脱机对数据库进行备份,即备份前必须让数据库停止运行,备份后必须重新启动数据库。
下面通过三种方式实现上下文管理器
- 经典方式,不调用库
- 使用
contextlib.contextmanager
进行生成器实现
- 使用
contextlib.ContextDecorator
装饰器实现
经典上下文管理器
在不使用任何标准库和第三方库情况下的经典实现如下
Python |
---|
| run = print
def stop_database():
run("systemctl stop postgresql.service")
def start_database():
run("systemctl start postgresql.service")
class DBHandler:
def __enter__(self):
stop_database()
return self
def __exit__(self, ex_type, ex_value, ex_traceback):
start_database()
def db_backup():
run("pg_dump database")
if __name__ == "__main__":
with DBHandler():
db_backup()
|
注意事项
- 一般而言,最好让
__enter__
返回一个值,用于管理上下文
__exit__
方法接收一些特殊值,用来处理异常,没有异常的情况下这些值默认为 None
基于 contextlib
的生成器实现
通过 contextlib.contextmanager
以及 yield
生成器方法实现
Python |
---|
| import contextlib
@contextlib.contextmanager
def db_handler():
try:
stop_database()
yield
finally:
start_database()
if __name__ == "__main__":
with db_handler():
db_backup()
|
基于 contextlib
的装饰器实现
通过继承 contextlib.ContextDecorator
类,可以很方便地以装饰器的形式实现上下文管理器,且其优点在于,装饰器只需要被定义一次,就可以处处复用。
Python |
---|
| import contextlib
class db_handler(contextlib.ContextDecorator):
def __enter__(self):
stop_database()
return self
def __exit__(self, ex_type, ex_value, ex_traceback):
start_database()
@db_handler()
def db_backup():
run("pg_dump database")
if __name__ == "__main__":
db_backup()
|
通过装饰器进行异常控制
在 contextlib
库中,我们可以使用 contextlib.suppress
来忽略特定的异常,示例如下
Python |
---|
| import contextlib
def div(a, b):
return a / b
if __name__ == "__main__":
with contextlib.suppress(ZeroDivisionError):
div(1, 0)
|
这样,就可以忽略除数为 0 的特殊情况。
参考