with语句与上下文管理器

目录

原文:https://www.cnblogs.com/nnnkkk/p/4309275.html

with语句

上下文管理器

contextlib模块


with语句

  •  with语句时在Python2.6中出现的新语句,此前需要使用try/finally代码结构,
  • f = open("test.txt")
    try:
        for line in f.readlines():
            print(line)
    finally:
        f.close()
  • with语句的基本语法结构如下 :
    • with expression [as variable]:
          with-block
      
      
      
      """
      应用如:
      with open("text.txt") as f:
          for line in f.readlines()
          print(line)
      
      """
    •  

      1.首先生成一个上下文管理器expression,在上面例子中with语句首先以“test.txt”作为参数生成一个上下文管理器open("test.txt")。

      2.然后执行expression.__enter__()。如果指定了[as variable]说明符,将__enter__()的返回值赋给variable。上例中open("test.txt").__enter__()返回的是一个文件对象给f。

      3.执行with-block语句块。上例中执行读取文件。

      4.执行expression.__exit__(),在__exit__()函数中可以进行资源清理工作。上面例子中就是执行文件的关闭操作 

上下文管理器

  • 上下文管理器就是实现了上下文协议的类,而上下文协议就是一个类要实现__enter__()和__exit__()两个方法
    • __enter__():主要执行一些环境准备工作,同时返回一资源对象。
      • 如上下文管理器open("test.txt")的__enter__()函数返回一个文件对象。
    • __exit__():资源清理工作。
      • 完整形式为__exit__(type, value, traceback),这三个参数分别为异常类型、异常信息和堆栈。如果执行体语句没有引发异常,则这三个参数均被设为None。否则,它们将包含上下文的异常信息
      • __exit__()方法返回值为True或False,分别指示被引发的异常有没有被处理。如果返回False,引发的异常将会被传递出上下文
        • 如果__exit__()函数内部引发了异常,则会覆盖掉执行体的中引发的异常
        • 处理异常时,不需要重新抛出异常,只需要返回False,with语句会检测__exit__()返回False来处理异常。
  • 如果我们要自定义一个上下文管理器,只需要定义一个类并且是实现__enter__()和__exit__()即可,以数据库的连接为例。
    • """
      通常的方法
      """
      
      def test_write():
          con = MySQLdb.connection()
          cursor = con.cursor()
          sql = """      #具体的sql语句
          """
          try:
              cursor.execute(sql)
              cursor.execute(sql)
              cursor.execute(sql)
              con.commit()      #提交事务
          except Exception as ex:
              con.rollback()    #事务执行失败,回滚数据库
      
      
      """
      with 方法
      """
      
      def test_write():
          sql = """      #具体的sql语句
          """
          con = DBConnection()
          with con as cursor:   
              cursor.execute(sql)
              cursor.execute(sql)
              cursor.execute(sql)
      
      
      def DBConnection(object):
          def __init__(self):
              pass
      
          def cursor(self):
              #返回一个游标并且启动一个事务
              pass
      
          def commit(self):
              #提交当前事务
              pass
      
          def rollback(self):
              #回滚当前事务
              pass
      
          def __enter__(self):
              #返回一个cursor
              cursor = self.cursor()
              return cursor
      
          def __exit__(self, type, value, tb):
              if tb is None:
                  #没有异常则提交事务
                  self.commit()
              else:
                  #有异常则回滚数据库
                  self.rollback()

contextlib模块

  • 需要实现一个上下文管理器,需要定义一个实现了__enter__和__exit__两个方法的类, 这显然不是很方便

  • contextlib模块包含一个装饰器contextmanager和一些辅助函数,装饰器contextmanager只需要写一个生成器函数就可以代替自定义的上下文管理器

    • """
      先使用yield先定义一个生成器函数
      """
      
      @contextmanager
      def some_generator(<arguments>):
          <setup>
          try:
              yield <value>
          finally:
              <cleanup>
      
      """
      然后便可以用with语句调用contextmanage生成的上下文管理器了,with语句用法如下
      """
      with some_generator(<arguments>) as <variable>:
          <body>
      
      
      """
      生成器函数some_generator就和我们普通的函数一样,它的原理如下:
      
      1、some_generator函数在在yield之前的代码等同于上下文管理器中的__enter__函数。
      2、yield的返回值等同于__enter__函数的返回值,即如果with语句声明了as <variable>,则yield的值会赋给variable
      3、然后执行<cleanup>代码块,等同于上下文管理器的__exit__函数。此时发生的任何异常都会再次通过yield函数返回。
      """

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值