zoukankan      html  css  js  c++  java
  • python上下文管理

    一、python上下文介绍:

      python中的上下文,指的就是代码所执行的环境状态,或者运行的场景

      python上下文管理器规定了某个对象的使用范围,当进入或者离开了使用范围,会有相应的操作,多用于资源的分配和释放上,即在开始时分配资源,结束时释放资源。

      如文件的读写,在读写前,需要先打开文件,在读写完成后,需要关闭文件。再如数据库的操作,在操作前,需要先连接数据库,结束后,需要释放连接等。

    二、上下文管理器的使用: 

      下面看看资源的创建和释放场景(以数据库的操作为例):

      
    class DataBase(object):
    
      def __init__(self):
    
        self.connect = False
      def connect(self):
    
        self.connect = True
          def close(self):
                self.connect = False
          def query(self):
                if self.connect:
                      return "query data"
                else:
                      raise ValueError("db not connected")
    
    def handle_query():
          db = DataBase()
          db.connect()
          print("db query:", db.query())
          db.close()
    
    if __name__=="__main__":
          handle_query()
    View Code

      上述代码很简单,针对数据类DataBase,我们提供了connect,close,query三个常规的db交互接口。

      普通的功能实现是没有问题的,但是我们都知道,在web交互中,数据库的操作是最频繁的,也就是说,我们每次在操作数据库的时候,都需要进行数据库类实例化,连接,关闭操作。显然这个和pythonic不符合的。

      然后为了上面的代码更加的优雅,我们想到了python中的一个黑魔法,装饰器

      我们可以将上述代码数据库的连接和关闭封装成一个闭包,然后通过装饰器对上面的代码进行改写:

    class DataBase(object):
        def __init__(self):
            self.connect = False
        def conn(self):
            self.connect = True
        def close(self):
            self.connect = False
        def query(self):
            if self.connect:
                return "query data"
            else:
                raise ValueError("db not connected")
    
    def dbconn(fun):
        def wrapper(*args, **kwargs):
            db = DataBase()
            db.conn()
            fun(db, *args, **kwargs)
            db.close()
        return wrapper
    
    @dbconn
    def handle_query(db=None):
        print("query:", db.query)
    
    if __name__=="__main__":
        handle_query()

      我们封装了一个dbconn的装饰器,通过使用@dbconn装饰器,实现了数据库连接和释放的代码的复用,对比上面的代码,可以发现,使用装饰器相对优雅了很多

      但是每个装饰器都需要先定义一下db的资源句柄,看起来还是没有那么优雅。下面我们通过上下文管理器的方式实现数据库操作:

    class DataBase(object):
        def __init__(self):
            self.connect = False
        def conn(self):
            self.connect = True
        def close(self):
            self.connect = False
        def query(self):
            return "query data"
        def __enter__(self):
            self.conn()
            return self
        def __exit__(self, exc_type, exc_value, exc_db):
            self.close()
    
    def handle_query():
        with DataBase() as db:
            print("query:", db.query)
    
    if __name__=="__main__":
            handle_query()

      对比上面的上下文管理器实现数据库操作的代码,可以发现,在定义数据库类DataBase的时候,虽然多写了几行代码,但是我们的代码可读性变得更好了。

    三、上下文管理协议

      实现了上下文协议的对象叫上下文管理器

      那么什么是上下文协议呢?即实现了__enter__() 和__exit__()方法,也就是实现了上下文管理协议

      上下文表达式必须要返回一个上下文管理器对象

      代码结构如下:

    class Context:
        def __init__(self, filename, fileMode="w"):
            self.obj = open(filename, fileMode)
        def __enter__(self):
            return self.obj
        def __exit__(self, exc_type, exc_value, exc_db):
            self.obj.close()
    
    with Context("C:UsersadminDesktop1.txt") as f:
            f.write("something")

      如上图,Context类实现了__enter__和__exit__两个上下文管理器协议,当Context被调用或实例化的时候,创建了上下文管理器

      配合with语句使用的时候,上下文管理器会自动调用__enter__方法,然后进入运行时上下文环境,并将__enter__函数返回值赋值给as从句变量 f

      当f.write("something")执行完毕退出with语句块或者是出现异常导致程序退出时,会执行__exit__方法,并把异常信息传递给后面的参数exc_type, exc_value, exc_db

      如果__exit__方法返回True,则with语句块不会显示的抛出异常,程序终止

      如果__exit__方法返回None或者False,异常会被主动抛出,程序终止。

    四、上下文管理器工具

      python为了使代码更加的优雅,还提供了一个模块contextlib 来实现更函数式的上下文管理器

    from contextlib import contextmanager
    
    @contextmanager
    def context(filename, fileMode="w"):
        f = open(filename, fileMode)
        try:
            yield f
        except Exception as e:
            print(e)
        finally:
            f.close()
    
            
    with context("C:\Users\admin\Desktop\1.txt") as f:
        f.write("write something1")

      上图通过contextmanager装饰器定义了一个上下文管理器函数context,通过with context("C:\Users\admin\Desktop\1.txt") 返回上下文管理器对象

      然后调用函数隐式的__enter__函数,并将结果通过yield返回

      然后通过返回的文件对象,执行文件的写入操作

      写入操作结束,退出上下文环境,执行了f.close()

    五、with语句执行过程总结:

      1)执行上下文表达式 Context("C:UsersadminDesktop1.txt"),获得上下文管理器

      2)加载上下文管理器的__enter__ 和 __exit__,以备后续调用

      3)调用__enter__(),方法,并返回文件对象 f 赋值给as从句变量

      4)执行with语句块的子语句块f.write("something")

      5)调用上下文管理器的__exit__(),如果是由于异常导致程序退出的,将type, value 和traceback作为参数传递给exit(),否则传三个None

         如果__exit__()返回值等于False,则异常会被显示的抛出,程序终止,否则,异常会被无视,继续执行。

       上下文管理器主要用于多线程/进程的变成中,因为涉及到上下文的切换

      

      

  • 相关阅读:
    用户代理列表--爬虫伪装浏览器访问用
    python爬虫解析页面数据的三种方式
    requests模块的使用
    Python pip源更改
    个人博客项目开发
    Django之中间件
    Django之发送邮件
    Django组件之用户认证组件
    Django之Cookie与session
    Django组件之分页器
  • 原文地址:https://www.cnblogs.com/fiona-zhong/p/10335009.html
Copyright © 2011-2022 走看看