zoukankan      html  css  js  c++  java
  • Python的上下文管理器探析

    上下文管理器

    上下文管理器对象存在的目的是管理with语句,就像迭代器的存在是为了管理for语句。
     
    上下文管理器协议包含__enter__和__exit__两个方法。
    with 语句开始运行时,会在上下文管理器对象上调用 __enter__ 方法。with 语句运行结束后,会在上下文管理器对象上调用 __exit__ 方法。
     
    举个例子:
    import sys
    
    class LookingClass:
        def __enter__(self):
            self.original_write = sys.stdout.write
            sys.stdout.write = self.reverse_write
            return 'JABBERWOCKY'
    
        def reverse_write(self, text):
            return self.original_write(text[::-1])
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            sys.stdout.write = self.original_write
            if exc_type is ZeroDivisionError:
                print('Please DO NOT divide by zero!')
                return True
    
    
    # 1 测试LookingClass
    with LookingClass() as what:
        print('Alice, Kitty and Snowdrop')
        print(what)
    
    
    # 这时with已经吧LookingClass关闭了
    print('Back to normal.')
    
    
    # 2 直接实例化LookingClass
    manager = LookingClass()
    print(manager)
    print(manager.__enter__())
    print(manager)  # 没有退出上下文管理器
    print(manager.__exit__(None, None, None))
    print(manager)  # 恢复正常

    使用@contextmanager

    这个装饰器把简单的生成器函数变成上下文管理器,这样就不用创建类去实现管理器协议了。
     
    yield 语句的作用是把函数的定义体分成两部分:yield 语句前面的所有代码在 with 块开始时(即解释器调用 __enter__ 方法时)执行,yield 语句后面的代码在 with 块结束时(即调用 __exit__ 方法时)执行。
     
    这个类的 __enter__ 方法有如下作用。
    (1) 调用生成器函数,保存生成器对象(这里把它称为 gen)。
    (2) 调用 next(gen),执行到 yield 关键字所在的位置。
    (3) 返回 next(gen) 产出的值,以便把产出的值绑定到 with/as 语句中的目标变量上。
     
    with 块终止时,__exit__ 方法会做以下几件事。
    (1) 检查有没有把异常传给 exc_type;如果有,调用 gen.throw(exception),在生成器函数
    定义体中包含 yield 关键字的那一行抛出异常。
    (2) 否则,调用 next(gen),继续执行生成器函数定义体中 yield 语句之后的代码。
     
    @contextmanager 装饰器优雅且实用,把三个不同的 Python 特性结合到了一起:函数装饰器、生成器和 with 语句

    举个例子:

    import sys
    import contextlib
    
    
    @contextlib.contextmanager
    def looking_class():
        original_value = sys.stdout.write
    
        def reverse_write(text):
            return original_value(text[::-1])
    
        sys.stdout.write = reverse_write
        # 增加处理__exit__方法时的异常
        msg = ''
        try:
            yield 'JABBERWOCKY'
        except ZeroDivisionError:
            msg = 'Please DO NOT divide by zero!'
        finally:
            sys.stdout.write = original_value
            if msg:
                print(msg)
    
    
    with looking_class() as wp:
        print('I love Python')
        print(wp)
    人生的路还很长,继续走吧
  • 相关阅读:
    Java Json 数据下划线与驼峰格式进行相互转换
    Java反射常用示例
    ApplicationContextAware 快速获取bean
    Spring AOP自动代理创建者
    Spring依赖检查
    Bean作用域实例
    注入值到Spring bean属性
    用javaConfig 代替 xml 配置
    spring使用@Autowired装载
    Spring 概述
  • 原文地址:https://www.cnblogs.com/jinggs/p/15118470.html
Copyright © 2011-2022 走看看