contextlib代码阅读

首先我们要知道 with协议。 然后我们看看 class _GeneratorContextManager(ContextDecorator, AbstractContextManager):

class _GeneratorContextManager(ContextDecorator, AbstractContextManager):
    def __init__(self, func, args, kwds):
        self.gen = func(*args, **kwds)
        self.func, self.args, self.kwds = func, args, kwds

    def __enter__(self):
        try:
            return next(self.gen)
        except StopIteration:
            raise RuntimeError("generator didn't yield") from None


def contextmanager(func):
    def inner(*args, **kwds):
        return _GeneratorContextManager(func, args, kwds)
    return inner

所以当我们调用的时候,例如:

In [1]: from contextlib import contextmanager

In [2]: @contextmanager
   ...: def foo(arg1, arg2, kwd=None):
   ...:     print('enter function foo with args and kwargs: %s, %s, %s' % (arg1, arg2, kwd))
   ...:     yield None
   ...:     print('leave function foo')
   ...:

In [3]: with foo(1, 2, "hello") as f:
   ...:     print('after yield, execute some ops')
   ...:
enter function foo with args and kwargs: 1, 2, hello
after yield, execute some ops
leave function foo

首先contextmanager将原本的foo函数替换成 foo=contextmanager(foo),其实就相当于 foo = inner,当执行 with foo(1, 2, "hello") as f的时候,首先执行 foo(1, 2, "hello") 相当于执行 inner(1, 2, "hello"),也就是执行 _GeneratorContextManager(foo, 1, 2, kwd="hello"), 然后会执行 _GeneratorContextManager__enter__ 返回给 f。这就是 这个decorator的作用。用代码里的注释来解释:

Typical usage:

    @contextmanager
    def some_generator(<arguments>):
        <setup>
        try:
            yield <value>
        finally:
            <cleanup>

This makes this:

    with some_generator(<arguments>) as <variable>:
        <body>

equivalent to this:

    <setup>
    try:
        <variable> = <value>
        <body>
    finally:
        <cleanup>

此外 contextlib 里还有 closing, redirect_stderr 等几个帮助函数,其实现原理 都和上面类似,打开代码 看看就知道了:)


更多文章
  • 我们真的需要这么复杂的技术栈吗?
  • Go设计模式:装饰器模式
  • 程序员的MySQL手册(一): 安装,基本配置
  • ElasticSearch学习笔记
  • Go设计模式:composite模式
  • 拯救删除ZFS之后的分区表
  • Linux使用redshift自动调整屏幕色温
  • Go设计模式:桥接模式和策略模式
  • Go设计模式:单例模式、原型模式和Builder模式
  • 操作系统也是CRUD
  • Go设计模式:简单工厂模式
  • 把USB设备穿透给虚拟机里的系统
  • debug故事之:事务让生活更美好
  • Go设计模式:模板模式
  • Go设计模式:适配器模式