如果我是正确的,with
语句不会为with
语句引入本地范围。
这些是来自Learning Python的例子:
with open(r'C:\misc\data') as myfile:
for line in myfile:
print(line)
...more code here...
和
lock = threading.Lock() # After: import threading
with lock:
# critical section of code
...access shared resources...
第二个示例是否等同于以下第一个示例的方式重写?
with threading.Lock() as lock:
# critical section of code
...access shared resources...
他们有什么不同?
第一个示例是否等同于以下类似于第二个示例重写的以下示例?
myfile = open(r'C:\misc\data')
with myfile:
for line in myfile:
print(line)
...more code here...
他们有什么不同?
答案 0 :(得分:4)
当with
进入上下文时,它会调用上下文管理器对象上的一个钩子,称为__enter__
,并且可以选择使用as <name>
将该钩子的返回值分配给一个名称。许多上下文管理器从self
挂钩返回__enter__
。如果他们这样做,那么您确实可以选择在单独的行上创建上下文管理器或使用as
捕获对象。
在您的两个示例中,只有从open()
返回的文件对象具有返回__enter__
的{{1}}挂钩。对于self
,threading.Lock()
返回与Lock.acquire()
相同的值,因此布尔值,而不是锁定对象本身。
您需要查找确认此信息的明确文档;然而,这并不总是那么清楚。对于__enter__
个对象,relevant section of the documentation个状态:
此模块提供的具有
Lock
和acquire()
方法的所有对象都可以用作release()
语句的上下文管理器。 在输入块时将调用with
方法,并在退出块时调用release()。
对于文件对象,IOBase
documentation相当模糊,你必须从示例中推断出文件对象的返回。
要带走的主要事情是返回acquire()
不是强制性的,也不总是需要。上下文管理员可以完全自由地返回其他内容。例如,许多数据库连接对象是允许您管理事务的上下文管理器(根据是否存在异常自动回滚或提交),其中enter返回绑定到连接的新游标对象。
明确:
对于您的self
示例,这两个示例的所有意图和目的完全相同。两者都调用open()
,如果不引发异常,则最终会引用名为open()
的文件对象。在这两种情况下,文件对象将在myfile
语句完成后关闭。 with
语句完成后,该名称仍然存在。
存在差异,但主要是技术性的。对于with
,创建文件对象,调用它的with open(...) as myfile:
方法然后绑定__enter__
。对于myfile
案例,首先绑定myfile = open(...)
,稍后调用myfile
。
对于您的__enter__
示例,使用with threading.Lock() as lock:
会将as lock
设置为lock
(锁定始终成功或以此方式无限制地阻止)。这与True
情况不同,lock = threading.Lock()
绑定到锁定对象。
答案 1 :(得分:1)
Here's a good explanation。我会解释关键部分:
with
语句可以被认为是这样的代码:set things up try: do something finally: tear things down
在这里,“设置”可能是打开文件,或者获取某种外部资源,然后“撕下来”将关闭文件,或者释放或删除资源。 try-finally结构保证始终执行“撕下来”部分,即使完成工作的代码没有完成。