Python with语句

时间:2020-02-23 14:43:40  来源:igfitidea点击:

Python with语句使我们在与上下文管理器一起工作时可以编写更简单的代码。
with语句是在PEP 343下的Python 2.5中引入的。

1.什么是上下文管理器?

上下文管理器是创建和管理运行时上下文的对象。
上下文管理器的典型用法是保存和还原全局状态,锁定和解锁资源,打开和关闭文件等。

2.上下文管理器的生命周期

上下文管理器对象必须定义enter()和exit()方法。
创建运行时上下文并销毁它们时将调用这些方法。

3.为什么我们需要带with语句的Python?

当我们必须使用文件时,我们必须首先打开它。
它为文件创建一个运行时上下文管理器。
工作完成后,我们必须手动关闭文件,以便上下文管理器正确终止。

我们通常使用try-except块来处理文件,最后使用块来关闭文件。
这样可以确保即使try块引发错误也可以关闭文件。

try:
  txt_file = open("abc.txt")
  # do some operations
  txt_file.close()
except FileNotFoundError as e:
  print(e)
finally:
  txt_file.close()

执行with块中的代码时,Python with语句负责调用上下文管理器的exit()方法。

让我们使用with语句重写上面的代码。

with open("abc.txt") as file:
  # do some operations
  print("Done")

该代码更易于阅读,我们不必担心每次都关闭文件。

4. Python与语句自定义上下文管理器示例

我们可以通过实现enter()和exit()方法来定义自己的自定义上下文管理器。

class MyContext:

  def __init__(self):
      print("init method of MyContext")

  def __enter__(self):
      print("entering context of MyContext")

  def __exit__(self, exc_type, exc_val, exc_tb):
      print("exit context of MyContext")

with MyContext() as my_context:
  print("my_context code")

输出:

init method of MyContext
entering context of MyContext
my_context code
exit context of MyContext
  • 上下文管理器已初始化。

  • 然后,为上下文管理器对象调用__enter __()方法。

  • with块中的代码被执行。

  • 最后,调用上下文管理器的__exit __()方法。

5.带有打开文件的Python

Python 3.1增强了with语句,以支持多个上下文管理器。
让我们看看如何使用with语句打开多个文件。

with open("abc.txt") as file1, open("abc.txt") as file2:
  pass

上面的代码等效于多个嵌套的with语句。

with open("abc.txt") as file1:
  with open("abc.txt") as file2:
      pass

6.具有语句异常情况的Python

如果with块中引发了异常,则将其类型,值和回溯作为参数传递给__exit __()。

如果__exit __()方法返回False,则重新引发异常。

class MyContext:

  def __init__(self):
      print("init method of MyContext")

  def __enter__(self):
      print("entering context of MyContext")

  def __exit__(self, exc_type, exc_val, exc_tb):
      print(f'exit context of MyContext - {exc_type} :: {exc_val} :: {exc_tb}')
      return False

with MyContext() as my_context:
  print("my_context code")
  raise TypeError("TypeError inside with block")

输出:

init method of MyContext
entering context of MyContext
my_context code
exit context of MyContext - <class 'TypeError'> :: TypeError inside with block :: <traceback object at 0x1044e8f48>
Traceback (most recent call last):
File "/Users/hyman/Documents/PycharmProjects/hello-world/theitroad/with_statement.py", line 32, in <module>
  raise TypeError("TypeError inside with block")
TypeError: TypeError inside with block

如果__exit __()方法返回True,则使用该异常并继续正常执行。

class MyContext:

  def __init__(self):
      print("init method of MyContext")

  def __enter__(self):
      print("entering context of MyContext")

  def __exit__(self, exc_type, exc_val, exc_tb):
      print(f'exit context of MyContext - {exc_type} :: {exc_val} :: {exc_tb}')
      return True

with MyContext() as my_context:
  print("my_context code")
  raise TypeError("TypeError inside with block")

print("Done")

输出:

init method of MyContext
entering context of MyContext
my_context code
exit context of MyContext - <class 'TypeError'> :: TypeError inside with block :: <traceback object at 0x102149e08>
Done