python中with语句与上下文管理器

参考:
https://blog.youkuaiyun.com/qq_42415326/article/details/91357447  深入理解Python3中with语句和上下文管理器
https://blog.youkuaiyun.com/mydistance/article/details/82730014 【Python】with及上下文管理器的原理和应用
 
 
with语句是种简化语法,适用于对资源访问场景,确保不论使用过程中发生何种异常都会执行必要的清理操作,释放资源。
  • 更加优雅的操作(创建/获取/释放)资源,如文件操作、数据库连接;
  • 更加优雅的处理异常;
 
一、with执行原理
    实际上,在文件操作时不是不需要写文件的关闭,而是文件的关闭操作在with的上下文管理器中的协议方法里已经写好。当文件操作执行完成后,with语句自动调用上下文管理器里的关闭语句来关闭文件资源。
 
with open('test.txt') as f:
    pass
 
1. 上下文表达式:with open('test.txt') as f:
2. 上下文管理器:open('test.txt')
3. f 不是上下文管理器,应该是资源对象。
 
 
二、上下文管理器
          ContextManager,在程序中用来表示代码执行过程中所处的前后环境。 上下文管理器中有__enter__和__exit__两个方法
    以with为例,__enter__方法会在执行with后面的语句时执行,一般用来处理操作前的内容,比如创建文件对象/数据库连接对象、初始化等;__exit__方法会在with内的代码执行完毕后执行,一般用来处理善后工作,比如文件的关闭、数据库的关闭等。
 
三、上下文管理器实现
要实现一个上下文管理器,只需要在类里实现__enter__和__exit__方法,这个类的实例就是一个上下文管理器。也可以利用python提供的装饰器,将函数变成上下文管理器。
 
3.1、自定义一个上下文管理器---类:
# -*- coding: utf-8 -*-

class MyOpen(object):
    def __init__(self, path, mode):
        # 记录要操作的文件路径和模式
        self.__path = path
        self.__mode = mode

    def __enter__(self):
        print('代码执行到了__enter__......')
        # 打开文件
        self.__handle = open(self.__path, self.__mode)
        # 返回打开的文件对象引用, 用来给  as 后的变量f赋值
        return self.__handle

    # 退出方法中,用来实现善后处理工作
    def __exit__(self, exc_type, exc_val, exc_tb): 
        print('代码执行到了__exit__......')
        self.__handle.close()


# a+ 打开一个文件用于读写。若该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。若该文件不存在,创建新文件用于读写。
with MyOpen('test.txt', 'a+') as f:
    # 创建写入文件
    f.write("Hello Python!!!")
    print("文件写入成功")

通过执行顺序,可以看到文件在写入前调用了 __enter__ 方法, 写入操作执行完之后,自动调用了 __exit__ 方法,做了善后处理工作。
 
注: __exit__ 方法
 
参数:
    __exit__ 方法中有三个参数,用来接收处理异常。 若主逻辑没有错误,这三个参数都返回None 。若代码在运行时发生异常,异常会被保存到这里。
    exc_type : 异常类型
    exc_val : 异常值
    exc_tb : 异常回溯追踪
 
返回值:
    __exit__方法的返回值决定了捕获的异常是否继续向外抛出:如果是 False 那么就会继续向外抛出,程序会看到系统提示的异常信息;如果是 True 不会向外抛出,程序看不到系统提示信息,只能看到else中的输出。
 
 
异常场景:
# -*- coding: utf-8 -*-


# 编写两个数做除法的程序,然后给除数穿入0
class MyCount(object):
    # 接收两个参数
    def __init__(self, x, y):
        self.__x = x
        self.__y = y

    # 返回一个地址(实质是被as后的变量接收),实例对象就会执行MyCount中的方法:div()
    def __enter__(self):
        print('代码执行到了__enter__......')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("代码执行到了__exit__......")
        if exc_type == None:
            print('程序没问题')
        else:
            print('程序有问题,如果你能你看懂,问题如下:')
            print('Type: ', exc_type)
            print('Value:', exc_val)
            print('TreacBack:', exc_tb)
        # 返回值决定了捕获的异常是否继续向外抛出
        # 如果是 False 那么就会继续向外抛出,程序会看到系统提示的异常信息
        # 如果是 True 不会向外抛出,程序看不到系统提示信息,只能看到else中的输出
        return False

    def div(self):
        print("代码执行到了除法div")
        return self.__x / self.__y


with MyCount(1, 0) as mc:
    mc.div()

 

 
 
 
3.2、自定义一个上下文管理器---函数:
       pyhon提供了一个装饰器, 只要按照它的代码协议来实现函数内容 ,就可以将这个函数对象变成一个上下文管理器。
在被装饰函数里, 必须是一个生成器(带yield),yield之前的代码相当于__enter__方法,yield之后的代码相当于_exit__方法
# -*- coding: utf-8 -*-
import contextlib

@contextlib.contextmanager
def open_func(file_name):
    # __enter__方法
    print('open file:', file_name, 'in __enter__')
    file_handler = open(file_name, 'r')

    try:
        yield file_handler
    except Exception as exc:
        # deal with exception
        print('the exception was thrown:%s' % exc)
    finally:
        print('close file:', file_name, 'in __exit__')
        file_handler.close()
        return

with open_func('test.txt') as file_in:
    for line in file_in:
        1 / 0
        print(line)

 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值