上下文管理器和else块

 

1、if 语句以外的 else块

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

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

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

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

 

▲ 在全部状况下,若是异常或者return、break或continue语句致使控制权跳到了复合语句的主块以外,else语句也会被跳过。对象

 

2、上下文管理器和 with 块

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

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

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

finally 子句中代码一般用于释放重要的资源,或者还原临时变动的转态。作用域

 

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

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对象

 

3、使用 @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语句中。

相关文章
相关标签/搜索