美文网首页Fluent Python
上下文管理器和else块

上下文管理器和else块

作者: 一块大番薯 | 来源:发表于2018-01-19 18:53 被阅读7次
  • for、while、try 语句的 else 子句
    其实把 else 当做 then 更好,当 for、while、try 没有异常、return、break、continue语句导致控制权调到符合语句的主板之外时,then 才会执行。

不好的做法,after_call 不属于易产生异常的语句,不应该放进 try:

 try:
    dangerous_call()
    after_call()
except OSError:
    log('OSError...')

好的做法,当没有产生异常时才执行 after_call。虽然作用效果一样,但是这种做法更符合逻辑:

try:
    dangerous_call()
except OSError:
    log('OSError...')
else:
    after_call()

EAFP:easier to ask for forgiveness than permission,获取原谅比获取许可容易。先干了再说。
先假定存在有效的键或属性,如果假定不成立再捕抓异常。代码中有很多 try 语句。
LBYL:leap before you leap,三思而后行。看准了才干。
事先检查。代码中有很多 if 语句

文件管理器和with块

文件管理器对象的存在是为了管理 with 语句,
迭代器的存在是为了管理 for 语句
文件管理器协议包含 _enter_ 和 _exit_ 两个方法。

  • 区分上下文管理器和 _enter_ 方法返回的对象
# 为 sys.stdout.write 打猴子补丁,替换成自己编写的方法
import sys

class LookingGrass:

    def __enter__(self):
        self.original_write, sys.stdout.write = sys.stdout.write, self.reverse_write
        return 'abcdefg'
        
    def reverse_write(self, text):
        return self.original_write(text[::-1])
        
    def __exit__(self, exc_type, exc_value, traceback):
        sys.stdout.write = self.original_write
上下文管理器
  • LookingGrass() 返回上下文管理器,是一个 LookingGrass 实例
  • as what 实质是上下文管理器调用 _enter_ 方法返回值绑定给 what
  • 上下文管理器管理 with 语句,所以输出都是反转的
  • 与函数和模块不同,with 块没有定义新的作用域,with 块外仍可以使用 what 变量
加深理解

@contextmanager

把简单的生成器函数变成上下文管理器,这样不用创建类来实现上下文管理器协议
生成器函数用到 yield,此处却与迭代无关,但由此可以引出协程(执行到某处,暂停,让客户代码运行,直至客户让协程继续执行)
yield 生成原本 _enter_ 方法返回的值,yield 后面是原本 _exit_ 的代码

import sys
from contextlib import contextmanager

@contextmanager
def looking_glass():
    orginal_write = sys.stdout.write
    
    def reverse_write(text):
        orginal_write(text[::-1])
        
    sys.stdout.write = reverse_write
    yield 'abcd'
    sys.stdout.write = orginal_write
contextmanage

但是,这种做法不够妥当,因为:
如果 with 块中抛出了异常,Python 解释器将其捕获,在 yield 表达式中再将其抛出
但是,那里没有处理错误的代码,函数 looking_glass 中止,无法恢复 sys.stdout.write,正确做法:

import sys
from contextlib import contextmanager

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

杂谈(with 块与子程序的互补)

如果有一系列操作如: A-B-C、P-B-Q,有两条路:

  • 把 B 拿出来,当作子程序
  • 把 A 和 C、P 和 Q 拿出来,当作 with 块

相关文章

  • chapter15 上下文管理器和else块

    主要讨论: with 语句和上下文管理器 for、while 和try语句的else子句 if语句之外的else块...

  • 上下文管理器和else块

    with语句会设置一个临时的上下文,交给上下文管理器对象控制,并且负责清理上下文。这么做能避免错误并减少样板代码。...

  • 上下文管理器和else块

    for、while、try 语句的 else 子句其实把 else 当做 then 更好,当 for、while、...

  • else 块 和上下文管理器

    else 块 我们知道在python 中最常用else的地方 就是 在if else 代码块中。而else 并不...

  • python的上下文管理器

    上下文管理器的概念 上下文管理器的任务是代码块执行前准备,代码块执行后收拾。 如何使用上下文管理器? 如何使用上下...

  • Python yield使用详解(二)

    上下文管理器和with块 with表达式 常见的with用法格式: 控制代码块的进入/退出 定制你自己的上下文管理...

  • Python学习打call第三十一天:上下文管理器

    1.什么是上下文管理 上下文管理器是一个包装任意代码块的对象,上下文管理器保证进入上下文管理器时,每次代码执行的一...

  • 关闭流要点2_with上下文管理_现场还原

    with语句(上下文管理器)with关键字(上下文管理器),可以自动管理上下文资源,无论什么原因跳出with块,都...

  • Python上下文管理器

    1.与装饰器的区别 上下文管理器是装饰器的近亲,装饰器用于包装函数,上下文管理器用于包装任意代码块. 上下文管理器...

  • Python上下文管理器

    上下文管理器 概念:实现了上下文协议的对象即为上下文管理器。 上下文管理器的协议: __enter__进入的方法_...

网友评论

    本文标题:上下文管理器和else块

    本文链接:https://www.haomeiwen.com/subject/ladooxtx.html