larken

勤奋的人生才有价值

导航

第15章 上下文管理器和else块

#《流流畅的Python》第15章 上下文管理器和else块
#15.1 先做这个,再做那个:if语句之外的else块
    #else子句不仅能在if语句中使用,还能在for、while和try语句中使用。
    #for/else、while/else和try/else的语义关系紧密,不过与if/else差别很大。
    #可是,在循环中,else的语义恰好相反:“运行这个循环,然后做那件事。
    #在Python中,try/except不仅用于处理错误,还常用于控制流程。
    #EAFP取得原谅比获得许可容易(easier to ask for forgiveness than permission)。
#15.2 上下文管理器和with块
    #上下文管理器协议包含 __enter__ 和 __exit__ 两个方法。
    #with语句开始运行时,会在上下文管理器对象上调用 __enter__ 方法。
    #with语句运行结束后,会在上下文管理器对象上调用 __exit__ 方法,以此扮演finally子句的角色。
with open('mirror.py')as fp:    #fp绑定到打开的文件上,因为文件的__enter__方法返回self。
    src=fp.read(60) #从fp中读取一些数据。
print(len(src))
print(fp)   #fp变量仍然可用。
print(fp.closed,fp.encoding)    #可以读取fp对象的属性。
fp.read()#但是不能在fp上执行I/O操作,因为在with块的末尾,调用TextIOWrapper.__exit__方法把文件关闭了。
#示例15-2 测试LookingGlass上下文管理器类
class LookingClass:
    def __enter__(self):
        import sys
        self.original_write=sys.stdout.write
        sys.stdout.write=self.reverse_write
        return 'JABBERWOCKY'
    def reverse_write(self,text):
        self.original_write(text[::-1])
    def __exit__(self, exc_type, exc_value, exc_traceback):
        # 如果一切正常Python调用__exit__方法时传入的参数是None,None, None;如果抛出了异常,这三个参数是异常数据,
        import sys
        sys.stdout.write=self.original_write
        if exc_traceback is ZeroDivisionError:
            print('Please DO NOT divide by zero')
            return True
with LookingClass() as what:
    print("Alice,kitty and Snowdrop")   #pordwonS dna yttik,ecilA
    print(what)     #YKCOWREBBAJ
print(what)     #JABBERWOCKY
print('Back to normal')     #Back to normal
#示例15-4 在with块之外使用LookingGlass类
manager=LookingClass()
print(manager)  #<__main__.LookingClass object at 0x004B5AB0>
monster=manager.__enter__()
print(monster=='JABBERWOCKY')   #eurT
print(monster)  #YKCOWREBBAJ
print(manager)  #>0BA50400x0 ta tcejbo ssalCgnikooL.__niam__<
print(monster)  #JABBERWOCKY'
#15.3 contextlib模块中的实用工具
#closing如果对象提供了close()方法,但没有实现__enter__/__exit__协议,那么可以使用这个函数构建上下文管理器。
#suppress构建临时忽略指定异常的上下文管理器。
#@contextmanager这个装饰器把简单的生成器函数变成上下文管理器,这样就不用创建类去实现管理器协议了。
#ContextDecorator这是个基类,用于定义基于类的上下文管理器。这种上下文管理器也能用于装饰函数,在受管理的上下文中运行整个函数。
#ExitStack这个上下文管理器能进入多个上下文管理器。with 块结束时,ExitStack 按照后进先出的顺序调用栈中各个上下文管理器的__exit__ 方法。
    #如果事先不知道 with 块要进入多少个上下文管理器,可以使用这个类。例如,同时打开任意一个文件列表中的所有文件。
#15.4 使用@contextmanager
#在使用 @contextmanager 装饰的生成器中,yield语句的作用是把函数的定义体分成两部分:
    #yield语句前面的所有代码在with块开始时(即解释器调用 __enter__ 方法时)执行,yield语句后面的代码在with 块结束时(即调用 __exit__ 方法时)执行。
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 'JABBERWOCKY'
    sys.stdout.write=original_write
with looking_glass() as what:
    print('Alice,kitty and Snowdrop')       #pordwonS dna yttik,ecilA
    print(what)     #YKCOWREBBAJ
print(what)     #JABBERWOCKY
#示例 15-8用于原地重写文件的上下文管理器
import csv
with inplace(csvfilename,'r',newline='') as(infh,outfh):
    reader=csv.reader(infh)
    writer=csv.writer(outfh)
    for row in reader:
        row += ['new','columns']
        writer.writerow(row)
#15.5 本章小结
#除了自动关闭打开的文件之外,with语句还有很多用途。
#@contextmanager装饰器优雅且实用,把三个不同的Python特性结合到了一起:函数装饰器、生成器和with语句。

 

posted on 2018-08-29 22:19  larken  阅读(140)  评论(0编辑  收藏  举报