python — 上下文管理器(例子:python连接数据库)

上下文管理器

概念

上下文管理器是装饰器的近亲,与装饰器类似的,它们都是包装其他代码的工具 ,一般用在自动释放,资源回收上面

  • 装饰器:包装用于定义的代码块
  • 上下文管理器:可以包装任意格式的代码块
什么是上下文管理器

上下文管理器是一个包装任意代码块的对象,上下文管理器保证:

  • 进入上下文管理器时,每次代码执行的一致性
  • 当退出上下文管理器时,相关的资源会被正确地回收(即使内部代码出错,退出步骤也会执行)
上下文管理器的应用
  • 上下文管理器被用到最多的就是——作为确保资源正确清理的一种方式

上下文管理器的语法

with语句

  • python2.5中加入的关键字with
  • with语句仅仅能对支持上下文管理协议的对象使用。
  • with语句的表达式的作用是返回一个遵循特定协议的对象,具体来说,该对象必须定义一个**__enter__方法和__exit__**方法

支持上下文管理器协议的对象

  • file
  • decimal.Context
  • thread.LockType
  • threading.Lock
  • threading.RLock
  • threading.Condition
  • threading.Semaphore
  • threading.BoundedSemaphore

with语句执行的解析

  • 语法:
    with context_expr as cm:
    do_sth()
  • 当with语句执行时,便执行上下文表达式(context_expr)来获得一个上下文管理器对象,上下文
    管理器的职责是提供一个上下文对象,用于在with语句块中处理细节:
    • 一旦获得了上下文对象,就会调用它的__enter__()方法
    • 将完成with语句块执行前的所有准备工作
    • 如果with语句后面跟了as语句,方法返回的结果会被赋值给as关键字后面的变量
    • 除了self参数,__enter__方法不接受任何其他参数。
    • __enter__方法一般负责执行一些配置
  • 当with语句块结束时,无论是正常结束,还是由于异常,都会调用上下文对象的__exit__()方法
    • __exit__()方法有3个参数
    • 如果with语句正常结束,三个参数全部都是 None
    • 如果发生异常,三个参数的值分别等于调用sys.exc_info()函数返回的三个值:类型(异常类)、值(异常实例)和跟踪记录(traceback),相应的跟踪记录对象。
    • 因为上下文管理器主要作用于共享资源,__enter__()和__exit__()方法基本是完成的是分配和释放资源的低层次工作,比如:数据库连接、锁分配、信号量加/减、状态管理、文件打开/关
      闭、异常处理等。
__exit__ 的三个参数
  • exc_type
  • exc_val
  • exc_tb
class ContestManger():
    def __init__(self,fp):
        self.fp = fp
    def __enter__(self):
        print("enter called")
    #必须接受三个参数
    def __exit__(self,exc_type,exc_val,exc_tb):
        print("exit called")
        print("exc_type:",exc_type)
        print("exc_val:",exc_val)
        print("exc_tb",exc_tb)
        self.fp.close()
        #return True
        #手动返回True,中止异常,上下文管理器包裹的代码后面的代码还可以正常运行,比如这里with cm01代码段不会继续运行,print("end..")会执行

fp = open("test.txt","a+")
cm01 = ContestManger(fp)
with cm01:
    1/0
    print("wirte cm01")
    fp.write("this is cm01 test")
print("end...........")

输出:
enter called
exit called
exc_type: <class 'ZeroDivisionError'>
exc_val: division by zero
exc_tb <traceback object at 0x0000020419D74500>
Traceback (most recent call last):
  File "E:\python\tianlongbabu\2022-08-12 上下文管理器\01.上下文管理器.py", line 17, in <module>
    1/0
ZeroDivisionError: division by zero
#没有1/0的话三个参数就都是None

上下文管理器异常处理

上下文管理器必须定义__exit__方法,该方法可以选择性地处理包装代码块中出现的异常,或者处理其他需要关闭上下文状态的事情
__exit__方法接收了异常信息,就有处理这个异常的义务,通常可以做以下几件:

  • 传播异常
  • 中止异常
  • 抛出不同异

使用contexttlib实现上下文管理器

contextlib模块介绍
  • contextlib模块实现上下文自动管理
  • 这个生成器可以用更简单的方法创建上下文管理器
from contextlib import contextmanager

@contextmanager
def mycontext():
    print("enter context")
    yield
    print("exit context")

with mycontext():
    print("my context.....")
使用上下文管理器连接数据库
import pymysql
class ConMysql():
    def __init__(self):
        self.con = None
        self.cursor_con = None
    def __enter__(self):
        print("connceting mysql ....")
        self.con = pymysql.connect(
            host="192.168.174.130",
            port=3306,
            user="sc",
            password="123456",
            database="sc"
        )
        self.cursor_con = self.con.cursor()
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.con:
            print("close mysql conncet...")
            self.con.close()

# cm = ConMysql()
with ConMysql() as cm:
    sql = "select * from userinfo"
    cm.cursor_con.execute(sql)
    print(cm.cursor_con.fetchall())
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值