Python上下文管理器

Python上下文管理器

简介

最近用到这个,仔细了解了一下,感觉是十分有用的,记录一下

使用场景

当我们需要获取一个临时打开的资源,并在使用完毕后进行资源释放和异常处理,利用try-catch语句可以完成,举个例子。
打开文件:

f = None
try:
    print("try")
    f = open("__init__.py", "r")
    print(f.read())
except Exception as e:
    print("exception")
finally:
    if f:
        print("finally")
        f.close()

利用上下文管理器:

class OpenHandle:

    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def __enter__(self):
        self.f = open(self.filename, self.mode)
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            print("exception")
        else:
            print("normal")
        self.f.close()

with OpenHandle("book.txt", "r") as f:
    print(f.read())

这样可以利用with-as语句改写代码,让程序员关注业务主流程,去掉对于资源的获取和关闭这些重复操作。提升代码的可读性。好处很大。

执行顺序

执行顺序是理解这种写法的关键:

  1. 初始化,执行handle的__init__()
  2. __enter__()方法,获取资源对象,返回给as后的变量
  3. 业务代码逻辑
  4. __exit__方法,传入3个参数,异常类型,异常对象,调用栈对象,无异常都为None
  5. 抛出异常或者正常结束

函数式上下文管理器

利用from contextlib import contextmanager这个装饰器可以将函数装饰为上下文管理器,其实这个装饰背后也是返回一个实现了__enter__和__exit__方法的类

from contextlib import contextmanager

@contextmanager
def managed_resource(*args, **kwds):
    # Code to acquire resource, e.g.:
    resource = acquire_resource(*args, **kwds)
    try:
        yield resource
    finally:
        # Code to release resource, e.g.:
        release_resource(resource)

>>> with managed_resource(timeout=3600) as resource:
...     # Resource is released at the end of this block,
...     # even if code in the block raises an exception

模板代码

sqlalchemy会话上下文管理器

利用这个管理sqlalchemy会话对象的获取和释放,控制事务是再合适不过了

class DbTransaction:

    def __init__(self, session_maker):
        self.session_maker = session_maker

    def __enter__(self):
        self.session = self.session_maker()
        # self.session.begin()   #如果session_make()是auto_commit=True就要写
        return self.session

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            self.session.rollback()
        else:
            self.session.commit()
        self.session.close()
        return False if exc_type else True
posted @ 2019-11-12 15:48  happy_codes  阅读(102)  评论(0编辑  收藏