zoukankan      html  css  js  c++  java
  • 上下文管理器和else块

    一、if 语句之外的 else块

      else 子句不仅能在 if 语句中使用,还能在for、while和try语句中使用。

      (1)for :仅当 for 循环运行完毕时(即 for 循环没有被break语句中止)才运行else 块,

      (2)while :仅当 while 循环因为条件为False 而退出时(即 while 循环没有被break语句中止)才运行else 块

      (3)try :仅当 try 块中没有异常抛出时才运行 else 块。else子句抛出的异常不会由前面的except子句处理。

    ▲ 在所有情况下,如果异常或者return、break或continue语句导致控制权跳到了复合语句的主块之外,else语句也会被跳过。

    二、上下文管理器和 with 块

    上下文管理器对象存在的目的是管理with语句,就像迭代器的存在是为了管理for语句一样。

    with 语句的目的是简化 try/finally 模式。

    这种模式用于保证一段代码运行完毕后执行某项操作,即便那段代码由于异常、return语句或sys.exit() 调用而中止,也会执行指定的操作。

    finally 子句中代码通常用于释放重要的资源,或者还原临时变更的转态。

    上下文管理器协议包含 __enter__ 和 __exit__ 两个方法。

    with语句开始运行时,会在上下文管理器对象上调用__enter__方法。

    with语句结束运行时,会在上下文管理器对象上调用__exit__ 方法,以此扮演finally子句的角色。

    ▲ 与函数的模块不同,with块没有定义新的作用域。

    上下文管理器类代码:

    class LookingGlass:
    
        def __enter__(self):
            import sys
            self.original_write = sys.stdout.write
            sys.stdout.write = self.reverse_write
            return 'ABCDEFGHIJK'
    
        def reverse_write(self,text):
            self.original_write(text[::-1])
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            import sys
            sys.stdout.write = self.original_write
            if exc_type is ZeroDivisionError:
                print('Please Do not divide by zero')
                return True
    
    with LookingGlass() as what:
        print('Alice,Kitty and Snowdrop')
        print(what)
    
    # pordwonS dna yttiK,ecilA
    # KJIHGFEDCBA

    __enter__方法返回的对象,存放在with语句的 as xxx对象中。

    如果__exit__方法返回None,或者True之外的值,with块中的任何异常都会向上冒泡。

    传给__exit__方法的三个参数列举:exc_type:异常类;exc_value:异常实例;traceback:traceback对象

    三、使用 @contextmanager

    @contextmanager 装饰器能减少创建上下文管理器的样板代码量;

    因为不用编写一个完整的类,定义__enter__和__exit__方法,而只需实现有一个yield 语句的生成器,生成想让__enter__方法返回的值。

    在使用@contextmanager 装饰的生成器中,yield语句作用是把函数的定义体分成两部分:

    yield语句前面的所有代码在with块开始时执行,yield语句后面的代码在with块结束时执行。

    import contextlib
    
    @contextlib.contextmanager
    def looking_glass():
    
        import sys
        original_write = sys.stdout.write
    
        def reverse_write(text):
            original_write(text[::-1])
    
        sys.stdout.write = reverse_write
        yield 'ABCDEFGHIJK'
        sys.stdout.write = original_write
    
    with looking_glass() as what:
        print('Alice,Kitty and Snowdrop')
        print(what)
    
    # pordwonS dna yttiK,ecilA
    # KJIHGFEDCBA

    ▲ 如果在with块中抛出异常,Python解释器会将其捕获,然后在yield表达式里再次抛出。需要在此处处理异常。

    @contextlib.contextmanager
    def looking_glass():
    
        import sys
        original_write = sys.stdout.write
    
        def reverse_write(text):
            original_write(text[::-1])
    
        sys.stdout.write = reverse_write
        
        msg = ''
        try:
            yield 'ABCDEFGHIJK'
        except ZeroDivisionError:
            msg = 'Please Do not divide by zero'
        finally:
            sys.stdout.write = original_write
            if msg:
                print(msg)

    ▲ 使用@contextmanager 装饰器时,要把yield语句放在 try/finally 语句中,或者放在with语句中。

  • 相关阅读:
    C#开发代码的小技巧1
    17. 装箱、拆箱的最小化
    Google Map开发(一) ASP.NET中调用Google Map API实现简单的地图显示
    C#可空类型
    C#如何扩展类型的内置方法
    Linq合并两个DataTable
    <br style="clear:both" /><br />
    GridView内容<br />换行
    数据库连接字符串大全
    JS将Table导出到Excel
  • 原文地址:https://www.cnblogs.com/5poi/p/11437229.html
Copyright © 2011-2022 走看看