首页 > temp > python入门教程 >
-
【Python】笔记:上下文管理器和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 模块中的实用工具
使用 @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)
__EOF__