一文带你搞懂Python上下文管理器

2022-01-24,

目录
  • 一、什么是上下文管理器
  • 二、如何实现上下文管理器
    • 1. 通过类实现
      • 1)_enter_
      • 2)_exit_
    • 2. 通过contextlib实现
    • 总结

      一、什么是上下文管理器

      我们在处理文件的时候经常看到下面这样的代码,它即是上下文管理器:

      with open('test.txt', encoding='utf-8') as f:
          print(f.readlines())
      

      它的含义是打开当前目录下的test.txt文件并打印它里面的内容,与下面的代码效果是一样的:

      f = open('test.txt', encoding='utf-8')
      print(f.readlines())
      f.close()
      

      对比两种写法能够发现,使用with自动执行了f.close()(关闭文件)的这步操作,能够少写一点代码。

      那这样的上下文管理器是怎么实现的,下面为你讲解。

      二、如何实现上下文管理器

      1. 通过类实现

      如果要实现上面open的上下文管理器功能,我们可以通过创建一个类,并添加__enter____exit__方法即可,如下面的代码所示:

      class DiyOpen(object):
      
          def __init__(self, filename, **kwargs):
              self.f = open(filename, **kwargs)
      
          def __enter__(self):
              return self.f
      
          def __exit__(self, exc_type, exc_val, exc_tb):
              print('关闭文件')
              self.f.close()
      
      
      with DiyOpen('test.txt', encoding='utf-8') as f:
          print(f.readlines())
      

      输出结果

      ['第一行\n', '第二行\n', '第三行']
      关闭文件

      可以看到在我们打印出文件内容后,自动执行了关闭文件的操作。

      __enter____exit__的含义是什么,__exit__后面的exc_type, exc_val, exc_tb又是什么意思呢?

      1)_enter_

      __enter__相对来说好理解的多,当出现with语句时,它就会被触发,有返回值时,会把返回值赋值给as声明的变量,也就是我们上面的as f中的f。

      2)_exit_

      __exit__是在with执行完成后自动执行的,他后面的参数含义如下:

      • exc_type:异常类型
      • exc_val:异常原因e
      • xc_tb:堆栈追踪信息

      当with中执行的代码报错时,除了不继续执行with包含的代码外,还会将报错信息放入上面的三个参数中,例如下面的代码:

      class DiyOpen(object):
      
          def __init__(self, filename, **kwargs):
              self.f = open(filename, **kwargs)
      
          def __enter__(self):
              return self.f
      
          def __exit__(self, exc_type, exc_val, exc_tb):
              print(exc_type)
              print(exc_val)
              print(exc_tb)
              self.f.close()
      
      
      with DiyOpen('test.txt', encoding='utf-8') as f:
          print(f.no())
      

      输出结果

      <class 'AttributeError'>
      '_io.TextIOWrapper' object has no attribute 'no'
      <traceback object at 0x000002A34B834900>

      需要注意的是:

      • 我们可以手动指定__exit__的返回值为True让它不报错。
      • 没有异常信息时,上面的三个参数值都会为None

      2. 通过contextlib实现

      Python内置了contextlib这个模块用于实现上下文管理器,它是通过生成器yield实现的,这个模块让我们不必再创建类和__enter__和__exit__了。

      通过contextlib实现open功能的代码如下:

      from contextlib import contextmanager
      
      @contextmanager
      def diy_open(filename, **kwargs):
          f = open(filename, **kwargs)  # __init__
          try:
              yield f  # __enter__
          finally:  # __exit__
              f.close()
      
      with diy_open('test.txt', encoding='utf-8') as f:
          print(f.readlines())
      

      总结

      本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注北冥有鱼的更多内容!

      您可能感兴趣的文章:

      • C语言实现班级学生管理系统
      • C语言不用链表完成学生管理系统(完整代码)
      • C语言单链表实现学生管理系统
      • C语言实现学生管理系统
      • C语言链表实现学生管理系统
      • C语言实现简单学生管理系统

      《一文带你搞懂Python上下文管理器.doc》

      下载本文的Word格式文档,以方便收藏与打印。

      • python中bool的应用场景有哪些
        python中bool的应用场景有哪些

        条件判断:在条件语句中使用bool类型来判断条件是否成立,例如if语句、while循环等。 函数返回值:函数可以返回bool类型的值,表示函数执行的结果是真或假。 列表操作:bool类型可以用来判断列表中元素是否...

        2024-05-18编程代码
      • 怎么使用python编写简单鸡兔同笼程序
        怎么使用python编写简单鸡兔同笼程序

        以下是一个简单的用Python编写的鸡兔同笼程序示例: def calculate_animals(heads, legs): for num_chickens in range(heads+1): num_rabbits = heads - num_chickens if 2*num_chickens + 4...

        2024-05-18编程代码
      • python任意进制转换的方法是什么
        python任意进制转换的方法是什么

        Python中可以使用内置函数bin(), oct(), hex()来进行任意进制之间的转换。具体方法如下: 十进制转二进制:bin(number),将十进制数转换为二进制数。 decimal_num = 10 binary_num = bin(decimal_num) print(bi...

        2024-05-18编程代码
      • python怎么去掉重复数据
        python怎么去掉重复数据

        可以通过使用set()来去掉重复数据。以下是一个示例代码: data = [1, 2, 3, 4, 4, 5, 6, 6, 7] unique_data = list(set(data)) print(unique_data) 在这个示例中,将列表data转换为集合set,然后再转换为列表...

        2024-05-18编程代码
      • python列表重复元素怎么删除
        python列表重复元素怎么删除

        有多种方法可以删除Python列表中的重复元素,以下是其中一种方法: # 创建一个包含重复元素的列表 lst = [1, 2, 3, 1, 2, 3, 4, 5] # 使用set()函数将列表转换为集合,集合不允许有重复元素 unique_lst = list(s...

        2024-05-18编程代码
      • python中怎么去掉重复项
        python中怎么去掉重复项

        在Python中,可以使用set()函数来去掉列表中的重复项。 例如,假设有一个包含重复元素的列表: my_list = [1, 2, 3, 1, 2, 3, 4, 5] 可以使用set()函数将该列表转换为一个集合,然后再将集合转换回列表: new_li...

        2024-05-18编程代码
      • python中len函数的使用方法是什么
        python中len函数的使用方法是什么

        在Python中,len()函数用于返回指定对象的长度或者元素个数。它可以接受字符串、列表、元组、集合、字典等对象作为参数,并返回它们的长度。例如: # 字符串长度 s = "hello" print(len(s)) # 输出 5 ...

        2024-05-15编程代码
      • python如何把字符串拆开
        python如何把字符串拆开

        Python可以使用split()方法将字符串拆分为多个子字符串。split()方法接受一个分隔符作为参数,并返回一个包含拆分后的子字符串的列表。 例如,以下代码展示了如何将一个字符串按照空格进行拆分: s = "Hello...

        2024-05-15编程代码