"""
模块:python3 with.py
参考:
https://docs.python.org/zh-cn/3/reference/compound_stmts.html#with
https://docs.python.org/zh-cn/3/reference/datamodel.html#context-managers
https://blog.csdn.net/lxy210781/article/details/81176687
知识点:
0.with 语句用于包装带有使用上下文管理器 (参见 with 语句上下文管理器 一节) 定义的方法的代码块的执行。
with_stmt ::= "with" with_item ("," with_item)* ":" suite
with_item ::= expression ["as" target]
带有一个“项目”的 with 语句的执行过程如下:
1.对上下文表达式 (在 with_item 中给出的表达式) 求值以获得一个上下文管理器。
2.载入上下文管理器的 __enter__() 以便后续使用。
3.载入上下文管理器的 __exit__() 以便后续使用。
4.发起调用上下文管理器的 __enter__() 方法。
5.如果 with 语句中包含一个目标,来自 __enter__() 的返回值将被赋值给它。
注解: with 语句会保证如果 __enter__() 方法返回时未发生错误,则 __exit__() 将总是被调用。
因此,如果在对目标列表赋值期间发生错误,则会将其视为在语句体内部发生的错误。
参见下面的第 6 步。
6.执行语句体。
7.发起调用上下文管理器的 __exit__() 方法。
如果语句体的退出是由异常导致的,则其类型、值和回溯信息将被作为参数传递给 __exit__()。
否则的话,将提供三个 None 参数。
如果语句体的退出是由异常导致的,并且来自 __exit__() 方法的返回值为假,则该异常会被重新引发。
如果返回值为真,则该异常会被抑制,并会继续执行 with 语句之后的语句。
如果语句体由于异常以外的任何原因退出,则来自 __exit__() 的返回值会被忽略,
并会在该类退出正常的发生位置继续执行。
实例:
1.with EXPRESSION as TARGET:
SUITE
2.如果有多个项目,则会视作存在多个 with 语句嵌套来处理多个上下文管理器:
with A() as a, B() as b:
SUITE
在语义上等价于:
with A() as a:
with B() as b:
SUITE
1.with 语句上下文管理器
上下文管理器 是一个对象,它定义了在执行 with 语句时要建立的运行时上下文。
上下文管理器处理进入和退出所需运行时上下文以执行代码块。
通常使用 with 语句(在 with 语句 中描述),但是也可以通过直接调用它们的方法来使用。
上下文管理器的典型用法包括保存和恢复各种全局状态,锁定和解锁资源,关闭打开的文件等等。
object.__enter__(self)
进入与此对象相关的运行时上下文。
with 语句将会绑定这个方法的返回值到 as 子句中指定的目标,如果有的话。
object.__exit__(self, exc_type, exc_value, traceback)
退出关联到此对象的运行时上下文。
各个参数描述了导致上下文退出的异常。
如果上下文是无异常地退出的,三个参数都将为 None。
如果提供了异常,并且希望方法屏蔽此异常(即避免其被传播),则应当返回真值。
否则的话,异常将在退出此方法时按正常流程处理。
请注意 __exit__() 方法不应该重新引发被传入的异常,这是调用者的责任。
"""
# 1.f 绑定了一个上下文管理器。
# 此处会自动调用文件的 close()。
with open(r'./明白牌.txt', 'r', encoding="utf-8") as f:
data = f.read()
# print("data:", data)
print(f.closed)
f = open("cs.txt")
print(f.closed)
# True
# False
#
# Process finished with exit code 0
# 2.无异常发生
class Test:
def __enter__(self):
print('__enter__() is called!')
return self
def dosomething(self):
print('do some thing!')
def __exit__(self, exc_type, exc_value, traceback):
print(f'type:{exc_type}')
print(f'value:{exc_value}')
print(f'trace:{traceback}')
print('__exit()__ is called!')
print("\n2.")
with Test() as sample:
sample.dosomething()
# __enter__() is called!
# do some thing!
# type:None
# value:None
# trace:None
# __exit()__ is called!
# 3.有异常发生时,会抛出异常的例子。
class Test:
def __enter__(self):
print('__enter__() is called!')
return self
def dosomething(self):
# x = 1 / 0
print('do some thing!')
def __exit__(self, exc_type, exc_value, traceback):
print(f'type:{exc_type}')
print(f'value:{exc_value}')
print(f'trace:{traceback}')
print('__exit()__ is called!')
print("\n3.")
with Test() as sample:
sample.dosomething()
# __enter__() is called!
# type:<class 'ZeroDivisionError'>
# value:division by zero
# trace:<traceback object at 0x000001B2B622AA80>
# __exit()__ is called!
# Process finished with exit code 1
# 4.有异常发生时,不抛出异常的例子:
class Test:
def __enter__(self):
print('__enter__() is called!')
return self
def dosomething(self):
x = 1 / 0
print('do some thing!')
def __exit__(self, exc_type, exc_value, traceback):
print(f'type:{exc_type}')
print(f'value:{exc_value}')
print(f'trace:{traceback}')
print('__exit()__ is called!')
return True
print("\n4.")
with Test() as sample:
sample.dosomething()
# __enter__() is called!
# type:<class 'ZeroDivisionError'>
# value:division by zero
# trace:<traceback object at 0x0000013DCDE4C040>
# __exit()__ is called!
# Process finished with exit code 0