【问题标题】:Using `and` instead of `,` when starting multiple context managers in `with` statement在 `with` 语句中启动多个上下文管理器时使用 `and` 而不是 `,`
【发布时间】:2021-05-09 14:57:49
【问题描述】:
【问题讨论】:
标签:
python
python-3.x
syntax
with-statement
contextmanager
【解决方案1】:
您所拥有的是带有and 运算符的表达式。 and 运算符在 falsey 时返回其第一个操作数,否则返回其第二个操作数。假设self.subTest(...) 返回的东西truthy,你的代码相当于:
ctx = self.subTest("Invalid input") and self.assertRaises(ValueError)
with ctx: ...
相当于:
self.subTest("Invalid input")
ctx = self.assertRaises(ValueError)
with ctx: ...
或者:
self.subTest("Invalid input")
with self.assertRaises(ValueError): ...
因此,充其量,您所拥有的可能具有误导性。在最坏的情况下这是一个错误,因为 subTest 的上下文管理器没有被使用。
如果 self.subTest 返回 falsey 值,则永远不会执行 self.assertRaises(...),这将是您的测试中的一个明显错误。
【解决方案2】:
除了@deceze 的出色回答之外,您可以很容易地观察到这一点:您只需要创建自己的上下文管理器。
运行以下代码:
class C:
def __init__(self, id):
self.id = id
def __enter__(self):
print(f'Entering {self.id}')
return self
def __exit__(self, exc_type, exc_value, traceback):
print(f'Exiting {self.id}')
return self
with C(0), C(1): print('with statement 1')
print()
with C(2) and C(3): print('with statement 2')
您会看到打印了以下输出:
Entering 0
Entering 1
with statement 1
Exiting 1
Exiting 0
Entering 3
with statement 2
Exiting 3
发生的情况是,对于第一个 with 语句,两个值按顺序输入,然后以相反的顺序退出(这些是 Python 的 with 语句的语义)。但是在第二个with 中,只处理了第二个项目(进入然后退出)——因为第一个项目被and 运算符丢弃了。