Fluent Python

上下文管理器和else块

2018-01-19  本文已影响7人  一块大番薯

不好的做法,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_ 两个方法。

# 为 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
上下文管理器 加深理解

@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,有两条路:

上一篇下一篇

猜你喜欢

热点阅读