【Python】笔记:上下文管理器和else快

上下文管理器和else快

类似于 then 的 else

for...else... 仅在 for 循环运行完毕后运行 else, 不能被 break

while...else... 仅在 while 条件为 false 而退出后运行 else, 不能被 break

try...else... 仅在 try 没有抛出异常后, 运行 else

注: 若存在 break, continue, return 把控制权跳到了复合语句的主块外, else 也会被跳过

for item in ('A', 'B', 'C'):
    if item == 'D':
        break
else:
    raise ValueError('No D')
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

Cell In [4], line 5
      3         break
      4 else:
----> 5     raise ValueError('No D')


ValueError: No D
try:
    print("RUA")
except OSError:
    print("WARMING")
else:
    print("after rua")
RUA
after rua

上下文管理器和with块

with 化简 try...finally... 模式

上下文管理器协议包含 __enter____exit__

with 后跟 上下文管理器对象

as xxx 可选

__exit__ 中返回 True 以外的值, with 中的任何异常会向上冒泡, 默认返回 None, 即会向上冒泡异常

with open(r'C:\Users\qiany\OneDrive\Document\Code\python\study\FluentPython\data\rua.txt') as fp:
    src = fp.read(60)
    print(src)

print(fp.encoding)  # fp 依旧可以使用(仅限读取属性)
print(fp.read(60))  # 不能在 fp 上执行 I/O 操作, 因为 with 末尾调用 __exit__将文件关闭了
ruaruaruaruaruaruaruaruaruaruaruaruaruaruaruaruaruaruaruarua
cp936



---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

Cell In [12], line 6
      3     print(src)
      5 print(fp.encoding)  # fp 依旧可以使用(仅限读取属性)
----> 6 print(fp.read(60))  # 不能在 fp 上执行 I/O 操作, 因为 with 末尾调用 __exit__将文件关闭了


ValueError: I/O operation on closed file.
class LookingGlass:
    def __enter__(self):  # Python 调用 enter 不会传入任何参数
        import sys
        self.original_write = sys.stdout.write
        sys.stdout.write = self.reverse_write  # 猴子补丁
        return 'RUAAAAA'

    def reverse_write(self, text):
        self.original_write(text[::-1])

    def __exit__(self, exc_type, exc_value, traceback):
        import sys  # python 会缓存导入的模块, 重复导入 sys 不会浪费资源
        sys.stdout.write = self.original_write
        if exc_type == ZeroDivisionError:
            print('Dont divide zero')
            return True  # __exit__中返回True以外的值, with中的任何异常会向上冒泡

print('--- 使用 with 方法 ---')
with LookingGlass() as what:
    print("QAQ233")
    print(what)

print("what", what)

print('--- 不使用 with 方法 ---')
manager = LookingGlass()
monster = manager.__enter__()
print(monster)
manager.__exit__(None, None, None)

--- 使用 with 方法 ---
332QAQ
AAAAAUR
what RUAAAAA
--- 不使用 with 方法 ---
AAAAAUR

exc_type 异常类 eg.ZeroDivisionError

exc_value 异常实例 exc_value.args 可捕获 Error(value)value

traceback traceback对象

contextlib 模块中的实用工具

方法 释义
closing 如果对象提供了 close() 方法, 但没有实现 __enter__/__exit__ 协议, 那么可通过这个函数构造上下文
suppress 构建临时忽略指定异常的上下文管理器
@contextmanager 生成器函数 变成 上下文管理器
ContextDecorator 基类, 用于定义 基于类 的上下文管理器
ExitStack 这个 上下文管理器 能进入 多个 上下文管理器。with 结束时, ExitStack后进先出 的顺序调用栈中各个上下文管理器的 __exit__。eg.同时打开多个文件

使用 @contextmanager

在使用 @contextmanager 装饰的生成器中, yield语句的作用是把函数的定义体分成两部分,

  • yield的代码在 with 块开始时(解释器调用 __enter__方法时) 执行

  • yield的代码在 with 块结束时(解释器调用 __exit__方法时) 执行

  • yield 的值绑定到 as 的目标变量上去

注意: yield 语句最好放在 try...finally... 或在 with 语句中, 因为我们永远不知道用户会在 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 'RUAAAAAA'
    sys.stdout.write = original_write

with looking_glass() as what:
    print("QAQ233")
    print(what)
332QAQ
AAAAAAUR
# 加入异常处理
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 'RUAAAAAA'
    except ZeroDivisionError:
        msg = 'Dont divie by zero'
    finally:
        sys.stdout.write = original_write
        if msg:
            print(msg)

with looking_glass() as what:
    print("QAQ233")
    print(what)
posted @ 2022-12-03 21:20  Zinc233  阅读(6)  评论(0编辑  收藏  举报