读书笔记:《流畅的Python》第15章 上下文管理器和else块

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

"""
本章内容提要:
    with语句和上下文管理器
    for while try语句的else子句
"""

# 15.1 先做这个,再做那个:if语句之外的else块

# else子句的行为
"""
for / else
    仅当for循环运行完毕(即没有被break终止)才运行else块
while / else
    仅当while循环因为条件为false退出(即没有被break终止)才运行else块
try/ else
    仅当try没有异常抛出时才运行else块,else子句抛出的异常不会由前面的except处理
在所有情况下,如果异常或者return\break\continue导致控制权跳到了符合语句的主块之外,
else子句也会被跳过.
其实这种情况从语义上来说使用then关键字更好,但是python没有then关键字,而且Guido讨厌添加新的关键字
"""

# 示例:
"""
for item in my_list:
    if item.flavor == 'banana':
        break 
else:
    raise ValueError('No banana flavor found')
"""

"""
try dangerous_call()
    after_call()
except OSError:
    log('OSError...')
"""
# 只有dangerous_call不抛出异常after_call()才会执行
# 为了清晰准确,try块中应该只放置只预期抛出语句异常的语句,因此像下面这样写 更好
"""
try dangerous_call()
except OSError:
    log('OSError...')
else:
    after_call()
"""

# python词汇表
"""
    EAFP(easier to ask for forgiveness than permission)
        取得原谅比获得许可容易
        这是一种常见的python编程风格
        ,先假定存在有效的键或者属性,如果假定不成立,则捕获异常
        所以代码中有很多的try...except块
    LBYL(look before you leap)
        三思而后行
        这种编程风格在调用函数或者查找属性之前,先显式地测试前提条件  
        代码中有很多的if块  
"""

# 15.2上下文管理器和with块
"""
上下文管理器对象存在的目的是管理with语句就像迭代器的存在是为了管理for语句一样
with语句的目的是简化try/finally模式
    这种模式用于保证一段代码运行完毕以后,一定执行某一项操作
    finally子句通常用于释放重要的资源
上下文管理器协议
    包含__enter__和__exit__两个方法
        with语句运行时,会在上下文管理器上调用__enter__方法
        with语句运行结束时,会在上下文管理器调用__exit__方法
        
"""

# 15-1示例:把文件对象当成上下文管理器使用
"""
with open("mirror.py",encoding='utf-8') as fp:  # ①
    src = fp.read(60)
print(len(src))
print(repr(fp))  # <_io.TextIOWrapper name='mirror.py' mode='r' encoding='utf-8'>
print(fp.closed, fp.encoding)  # True utf-8
fp.read(60)  # Traceback
"""

#① 执行with语句后面的表达式得到的结果是上下文管理器对象
# 不过把值绑定到了目标变量上(as子句)是在上下文管理器上调用__enter__方法的结果
# open()函数返回TextIOWrapper类的实例,而改实例的__enter__方法返回self
# 不过__enter__方法除了返回上下文管理器对象之外,还可能返回其他对象
# 不管控制流程以那种方式退出with块,都会在上下文管理器对象上调用__exit__方法,
# 而不是在__enter__返回的对象上调用
# with语句的as子句是可选的,对open函数来说,必须加上as子句,以便获取文件的引用
# 不过,有些上下文管理器会返回None,因为没有有用的对象能提供给用户

# 示例:测试LookingGlass上下文管理器类
"""
from mirror import LookingGlass
with LookingGlass() as what: # ①
    print("Alice,Kitty and Snowdrop") # ②
    print(what)
print(what)
print('Back to normal')
# ① 上下文管理器是LookingGlass类的实例,上下文管理器上调用__enter__方法,把返回的结果绑定到what上
"""

# 示例15-4 在with块之外使用LookingGlass类
"""
from mirror import LookingGlass
manager = LookingGlass()
print(repr(manager))
monster = manager.__enter__()
print(monster == 'JABBERWOCKY')
print(monster)
print(manager)
manager.__exit__(None,None,None)
print(monster)
"""

# 15.3标准库contextlib中的实用工具
"""
closing
    如果对象提供了close()方法,但没有实现__enter__和__exit__协议,
    那么可以使用这个函数构建上下文管理器
suppress
    构建临时忽略指定异常的上下文管理器
@contextmanager
    这个装饰器把简单的生成器函数变成上下文管理器这样就不用类去实现管理器协议了
ContextDecorator
    这是个基类,用于定义基于类的上下文管理器,这种上下文管理器也能用于装饰函数,
    在受管理的上下文中运行整个函数
ExitStack
    这个上下文管理器能够进入多个上下文管理器
    with块结束的时候, ExitStack按照后进先出的顺序调用栈中各个上下文管理器的__exit__方法
    如果事先不知道with块要进入多少个上下文管理器,可以实用这个类
    例如,同时打开任意一个文件列表中的所有文件
"""

# 15.4使用@contextmanager
# 这个装饰器能够减少创建上下文管理器的样板代码
# 只需要一个yield语句生成想让__enter__方法返回的值
# yield把函数的定义体分割成两个部分,yield前面的代码在with语句开始的时候执行(即调用__enter__时)\
# yield后面的语句在with块结束的时候执行(即调用__exit__时)

# 示例15-5 使用生成器实现的上下文管理器
# mirror_gen.py

# 示例15-7:mirror_gen_exc.py 基于生成器的上下文管理器,实现了异常 处理
# mirror.py LookingGlass上下文管理器类
# mirror.py LookingGlass上下文管理器类

class LookingGlass:
    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_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
# __exit__的参数
    # exc_type
    #     异常类,例如ZeroDivisionError
    # exc_val
    #     异常实例,有时会有参数传给异常构造方法,例如错误消息,这些参数可以使用
    #     exc_val.args获取
    # exc_tb
    #     traceback对象
mirror_gen.py
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
"""
实际上@contextlib.contextmanager会把函数包装成实现了__enter__和__exit__的方法的类
"""
if __name__ == '__main__':
    with looking_glass() as what:
        print("Alice,Kitty and Snowdrop")
        print(what)
print(what)
# 示例15-7:mirror_gen_exc.py 基于生成器的上下文管理器,实现了异常处理
# 示例15-7:mirror_gen_exc.py 基于生成器的上下文管理器,实现了异常 处理
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
    msg = ''
    try:
        yield 'JABBERWOCKY'
    except ZeroDivisionError:
        msg = 'Please DO NOT divide by 0!'
    finally:
        sys.stdout.write = original_write
        if msg:
            print(msg)
# 用于原地从写文件的上下文管理器
# 用于原地从写文件的上下文管理器
"""import csv
with inplace(csvfilename,'r',newline='') as (infh,outfh):
    reader = csv.reader(infh)
    writer = csv.write(outfh)
    for row in reader:
        row+=['new','columns']
        writer.writerow(row)
        """
# inpalce函数是一个上下文管理器,为同一个文件提供了两个句柄

35岁学python,也不知道为了啥?

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值