Python高级特性——上下文管理器

上下文管理器(Context manager):就是指支持上下文管理器协议的对象,也就是实现了__enter__()__exit__()方法的对象。
上下文管理器协议(Context Management Protocol):是指要实现对象的__enter__()__exit__()方法。

最近在写一个Python的项目时,用with挂接上下文管理器,从而实现对数据库的访问,这样做的好处是对连接数据库和关闭数据库这样的常规性操作一次封装好,以后只管调用就好。

以下是实现方案:

import mysql.connector

class UseDatabase(object):
          def __init__(self, config: dict):
                    self.configuration = config

          def __enter__(self) ->"cursor":
                    self.conn = mysql.connector.connect(**self.configuration)
                    self.cursor = self.conn.cursor()
                    return self.cursor

          def __exit__(self, exc_type, exc_value, exc_traceback):
                    self.conn.commit()
                    self.cursor.close()
                    self.conn.close()

这是我们基于上下文管理器协议实现的一个上下文管理器,主要是用于建立数据库的连接和释放。我们现在只需专心的处理与数据有关的操作。
下面是对这个上下文管理器的使用:

def log_request(req: 'flask_request', res: str) -> None:
    """Log details of the web request and the results."""

    with UseDatabase(app.config['dbconfig']) as cursor:
        _SQL = """insert into log
                  (phrase, letters, ip, browser_string, results)
                  values
                  (%s, %s, %s, %s, %s)"""
        cursor.execute(_SQL, (req.form['phrase'],
                              req.form['letters'],
                              req.remote_addr,
                              req.user_agent.browser,
                              res, ))

我们使用了with语句挂接上下文管理器:这个代码的执行过程是:

  • 我们调用UseDatabase(app.config['dbconfig'])这个生成一个上下文管理器。

  • 调用上下文管理器的__enter__方法,并将__enter__方法的返回值赋值给as字句中的cursor变量,这儿返回的是一个游标对象,用于数据库和python之间的通信

  • 执行语句体(指with语句包裹起来的代码)

  • 不管执行语句体的过程中是否发生异常,都要执行上下文管理器的__exit__方法。__exit__方法负责执行【清理工作】,如释放资源,关闭连接,关闭文件等。如果执行过程没有出现异常,或者语句体中执行了语句 break/continue/return,则以 None 作为参数调用 exit(None, None, None);如果执行过程中出现异常,则使用 sys.exc_info 得到的异常信息为参数调用 exit(exc_type, exc_value, exc_traceback);

  • 出现异常时,如果__exit__(type, value, traceback)返回False或者None,则重新抛出异常,交给with之外的语句逻辑来处理异常,如果返回True,则忽略异常,不对异常进行任何处理。

contextlib模块
除了在类中定义__enter__方法和__exit__方法来实现上下文管理器,我们还可以通过生成器函数(也就是带yield的函数)结合装饰器来实现上下文管理器。python中自带的contextlib模块就是用来做这个的。

contextlib模块提供了三个对象:装饰器对象contextmanager,函数nested和上下文管理器closing。其中,contextmanager是一个装饰器,用于装饰生成器函数。并返回一个上下管理器。需要注意的是,被装饰的生成器函数只能产生一个值,否则会产生 RuntimeError 异常。

from contextlib import contextmanager

@contextmanager
def point(x, y):
    print 'before yield'
    yield x * x + y * y
    print 'after yield'

with point(3, 4) as value:
    print 'value is: %s' % value

# output
before yield
value is: 25
after yield

可以看到,yield 产生的值赋给了 as 子句中的 value 变量。
另外,需要强调的是,虽然通过使用 contextmanager 装饰器,我们可以不必再编写__enter____exit__方法,但是『获取』和『清理』资源的操作仍需要我们自己编写:『获取』资源的操作定义在 yield 语句之前,『释放』资源的操作定义在 yield 语句之后。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值