为了确保即使在出现错误的情况下也能运行某些清理代码,try...finally 语句是 很有用的。这一语句有许多使用场景,例如:

• 关闭一个文件。

• 释放一个锁。

• 创建一个临时的代码补丁。

• 在特殊环境中运行受保护的代码。

with 语句为这些使用场景下的代码块包装提供了一种简单方法。即使该代码块引发

2.2 高级语法 55 了异常,你也可以在其执行前后调用一些代码。例如,处理文件通常采用这种方式:

   >>> hosts = open('/etc/hosts')

   >>> try:

   ...     for line in hosts:

   ...         if line.startswith('#'):

... continue

   ...         print(line.strip())

   ... finally:

   ...     hosts.close()

   ...

127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost

本示例只针对 Linux 系统,因为要读取位于 etc 文件 夹中的主机文件,但任何文本文件都可以用相同的方法 来处理。

利用 with 语句,上述代码可以重写为:

   >>> with open('/etc/hosts') as hosts:

   ...     for line in hosts:

       ...

   ...

   ...

   ...

   127.0.0.1

   255.255.255.255 broadcasthost

   ::1             localhost

在前面的示例中,open 的作用是上下文管理器,确保即使出现异常也要在执行完 for 循环之后关闭文件。

与这条语句兼容的其他项目是来自 threading 模块的类: • threading.Lock

• threading.RLock

• threading.Condition

• threading.Semaphore

• threading.BoundedSemaphore

一般语法和可能的实现

with 语句的一般语法的最简单形式如下:

if line.startswith('#'):

   continue

print(line.strip())

   localhost


56 第2章 语法最佳实践—类级别以下

with context_manager: # 代码块

...

此外,如果上下文管理器提供了上下文变量,可以用 as 子句保存为局部变量:

with context_manager as context: # 代码块

...

  注意,多个上下文管理器可以同时使用,如下所示:

       with A() as a, B() as b:

           ...

  这种写法等价于嵌套使用,如下所示:

       with A() as a:

           with B() as b:

...