使用with
withoutas
仍然可以获得完全相同的拆解;它只是不会为您提供表示上下文的新本地对象。
您想要这样做的原因是,有时上下文本身并不直接有用——换句话说,您只是将它用于上下文进入和退出的副作用。
例如,对于一个Lock
对象,您必须已经拥有该with
块才能使用的对象——因此,即使您在块中需要它,也没有理由将其重新绑定到另一个名称。当您contextlib.closing
在不是上下文管理器的对象上使用时也是如此 - 您已经拥有对象本身,所以谁在乎closing
产生什么?
使用类似的东西sh.sudo
,甚至没有一个你可以使用的对象,句号。
在某些情况下,上下文管理器的目的只是为了存储和自动恢复某些状态。例如,您可能想编写一个termios.tcsetattr
-stasher,以便您可以tty.setraw()
在块内调用。您不在乎存储对象的外观,您只关心它会自动恢复。
decimal.localcontext
可以以任何这些方式工作——你可以传递一个你已经拥有的对象(因此不需要一个新名称),或者传递一个未命名的临时对象,或者让它只是将当前上下文存储为自动恢复。但在任何这些情况下。
在某些混合情况下,有时您需要上下文,有时则不需要。例如,如果您只想让数据库事务自动提交,您可以编写with autocommit(db.begin()):
,因为您不会在块内访问它。但是如果你想让它自动回滚,除非你明确地提交它,你可能会写with autorollback(db.begin()) as trans:
,所以你可以trans.commit()
在块内。(当然,通常情况下,您实际上想要一个在正常退出时提交并在异常时回滚的事务,如PEP 343的transaction
示例。但我想不出一个更好的混合示例......)
PEP 343及其前身(PEP 310、PEP 340 以及与 343 相关联的其他内容)在一定程度上解释了所有这些,但可以理解的是,您不会在随便阅读时就明白这一点——有太多信息不是t 相关的,它主要只是解释了英里高的概述,然后是实现级别的细节,跳过了介于两者之间的所有内容。