with与上下文管理器

1、open、close方式的文件操作

(1)举例

def m1():
	f = open("source.txt", "w")
	f.write("大家好,我是xxx")
	f.close()

(2)使用open的弊端

如果在调用 write 的过程中,出现了异常进而导致后续代码无法继续执行,close 方法无法被正常调用,因此资源就会一直被该程序占用,无法及时释放占用的文件资源。

(3)对代码进行改进

f = open("source.txt", "w")
try:
    f.write("大家好,我是xxx")
except Exception as e:
    print("error:", e)
finally:
    f.close()

(4)改进版的好处

改良版本的程序是对可能发生异常的代码处进行 try 捕获,如果在 try 代码块中程序出现了异常,后续代码就不再执行,而直接跳转到 except 代码块。而无论如何,finally 块的代码最终都会被执行。因此,只要把 close 放在 finally 代码中,文件就一定会关闭。

2、使用with进行文件操作

(1)举例

  with open("source.txt", "r") as f:
        f.write("大家好,我是渣渣辉")

(2)使用with的好处

在执行完with代码块后,系统能够自动调用close()方法关闭文件,释放资源;语句简洁,代码量少。

(3)with的实现原理

建立在上下文管理器协议(实现__enter__和__exit__)之上。

3、上下文管理器(Context Manager)

(1)上下文管理器的概念

上下文管理器本质就是能够支持with操作。
任何实现了 enter() 和 exit() 方法的对象都可称之为上下文管理器,上下文管理器对象可以使用 with 关键字。

(2)实现上下文管理器的方式一

自定义一个上下文管理器类,让该类实现 enter() 和 exit() 方法。

class File(object):

    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def __enter__(self):
        print("进入上文,获取资源")
        self.f = open(self.filename, self.mode)
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("进入下文,关闭资源")
        self.f.close()


with File('source.txt', 'r') as f:
    file_data = f.read(20)
    print(file_data)



# 当with遇到上下文管理器时, 就会在执行语句体之前,先执行上下文管理器的__enter__方法,
# 然后再执行语句体, 执行完语句体后, 最后执行__exit__方法

# exc_type(exception_type):异常类型
# exc_val(exception_value): 异常值
# exc_tb(exception_traceback): 异常追踪信息

# 异常处理:
# 把异常的type, value, traceback传递给__exit__方法, 让__exit__方法处理异常
# 如果程序正常执行, 3个参数的均为None,__exit__返回的是True, 那么这个异常就被忽略;
# 如果程序出现异常, __exit__返回的是False, 那么这个异常将被with语句抛出

(3)实现上下文管理器的方式二

使用 contextlib 模块中的装饰器 contextmanager,通过 yield 将函数分割成两部分,yield 之前的语句在 enter 方法中执行,yield 之后的语句在 exit 方法中执行。在 yield 后面的值是函数的返回值。

from contextlib import contextmanager

@contextmanager
def myopen(file_name, mode):
    print("进入上文,获取资源")
    f = open(file_name, mode)
    try:
        yield f
    finally:
        print("进入下文,关闭资源")
        f.close()


with myopen('source.txt', 'r') as f:
    file_data = f.read(20)
    print(file_data)


# 所有yield 之前的代码会作为上下文管理器的enter()方法来执行
# 所有位于yield 之后的代码会作为exit()方法执行
# 如果有异常发生,则会在yield中抛出, 所以最好在对yield进行异常的捕获,
# 使用try、finally, 此时发生的任何异常都会再次通过yield函数返回

(4)上下文管理器的应用

用于资源的获取和释放,且可自动关闭 ,释放资源。

  • 锁资源自动获取和释放;
  • 文件打开后自动管理;
  • 数据库的连接

以数据的连接为例:

from pymysql import connect

class Jing_dong(object):

    def __init__(self, database_name, password):

        self.conn = connect(host='localhost', port=3306, db=str(database_name),
                            user='root', password=str(password), charset='utf8')
        self.cur = self.conn.cursor()

    def __enter__(self):
        return self.cur

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.cur.close()
        self.conn.close()

with Jing_dong('jing_dong', 'mysql') as f:
    content = f.execute('select * from goods_brands')
    t = f.fetchall()
    print(t)

总结

(1)Python 提供了 with 语法用于简化资源操作的后续清除操作,实现原理建立在上下文管理器协议(实现__enter__和__exit__)之上。
(2)with使用代码中如果在打开过程中发生异常,需要使用try-except进行捕获。
(3)Python 还提供了一个 contextmanager 装饰器,更进一步简化上下管理器的实现方式。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值