在语句中或之前评估和分配表达式

时间:2017-09-14 17:29:25

标签: python python-3.x with-statement contextmanager

如果我是正确的,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...

他们有什么不同?

2 个答案:

答案 0 :(得分:4)

with进入上下文时,它会调用上下文管理器对象上的一个钩子,称为__enter__,并且可以选择使用as <name>将该钩子的返回值分配给一个名称。许多上下文管理器从self挂钩返回__enter__。如果他们这样做,那么您确实可以选择在单独的行上创建上下文管理器或使用as捕获对象。

在您的两个示例中,只有从open()返回的文件对象具有返回__enter__的{​​{1}}挂钩。对于selfthreading.Lock()返回与Lock.acquire()相同的值,因此布尔值,而不是锁定对象本身。

您需要查找确认此信息的明确文档;然而,这并不总是那么清楚。对于__enter__个对象,relevant section of the documentation个状态:

  

此模块提供的具有Lockacquire()方法的所有对象都可以用作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结构保证始终执行“撕下来”部分,即使完成工作的代码没有完成。