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)
    人生的路还很长,继续走吧
  • 相关阅读:
    jmeter学习笔记(3)-jmeter结合fiddler
    jmeter学习笔记(2)—http信息头管理器+断言
    requests接口自动化9-共享session和传递cookie
    djangorestframework学习1-通过HyperlinkedModelSerializer,ModelViewSet,routers编写第一个接口
    requests接口自动化8-传递数据为xml形式的post请求:data
    requests接口自动化7-Multi/form-data文件上传形式的post请求:files
    requests接口自动化6-Body里json格式数据形式的post请求:json
    requests接口自动化5-表单参数形式的post请求:data
    requests接口自动化4-登录后才能访问的get请求,需共享cookie
    requests接口自动化3-url里带参数的get请求:params
  • 原文地址:https://www.cnblogs.com/jinggs/p/15118470.html
Copyright © 2011-2022 走看看