python基础——with与上下文管理器

with

with关键字是一个流操作,可以调用上下文管理器对象,也就是只要实现了上下文管理器协议就可以使用with关键字调用
应用场景:
对于一些事先需要准备数据,事后需要数据清理工作的任务使用with关键字很方便。
关于with很好的例子就是文件操作,打开文件获得一个句柄,对文件进行操作,关闭文件

xiaogu = "xiaogu is the man of imposing looking"
f = open("./xiaogu.txt""w")
contents = f.write(xiaogu)
f.close()

以上代码中先以写的方式打开文件,再往文件中写入内容,最后再关闭文件句柄。
现在这里就会存在一个问题,如果打开xiaogu.txt 文件时正常打开了,但是再写入文件的时候出现异常,即写入的不是一个字符串,而是列表或者字典类型,这样在没有关闭文件句柄的情况下抛出异常,如果这种情况大量存在,到最后可能连正常的文件操作都会出现问题。

解决办法1:使用异常捕获try/except/finilly

try:
	xiaogu = "xiaogu is the man of imposing looking"
	f = open("./xiaogu.txt", "w")
	contents = f.write(xiaogu)
except Exception as e:
	pass
finally:
	f.close()

以上这种方法可以解决文件读写造成异常没有及时关闭的情况,但是代码冗余

解决办法2:使用python内置的with关键字

xiaogu = "xiaogu is the man of imposing looking"
with open("./xiaogu.txt", "w") as f:
	f.write(xiaogu)

with使用很少的代码同样可以解决文件异常关闭的问题,也就是说即使文件读写出现异常依然可以关闭文件句柄,具体with的工作原理,先来看一个概念:上下文管理器

上下文管理器

上下文:就是在需要执行代码的前边的代码叫上文,在需要执行的代码的后边的代码叫下文。
上下文管理器:如果一个对象中实现了__enter__()方法和__exit__()方法,那么这个对象就是一个上下文管理器,其中__enter__()方法返回资源对象,exit()方法主要是做一些善后工作
自定义一个上下文管理器:

class Work():
    def __init__(self, name, work):
        self.name = name
        self.work = work

    def __enter__(self):
        print(self.name)
        return self
	
	def func(self):
		print("xiaogu is the man of imposing looking")
		print(1/0)

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(self.work)


with Work("xiaogu", "testing") as f:
    f.func()

输出:
xiaogu
xiaogu is the man of imposing looking
testing
with的工作原理:

在代码执行到with Work(“xiaogu”, “testing”) as f:时,with首先会先查看Work()对象是不是一个上下文管理器对象,即Work()对象中是否实现了__enter__()方法和__exit__()方法,如果没有这两个方法,with会直接抛异常,如果有这两个方法,with会首先调用Work()对象中的__enter__()方法,把自身对象的引用返回,并把返回值会赋给f,f在调用work()对象中的其他方法时出现异常,程序还是会向外抛出异常,但是程序也会自动调用__exit__()方法,处理善后工作。
另一种实现上下文管理器的方式:使用python内置的contextlib库

import time
from contextlib import contextmanager


@contextmanager
def func():
    print("xiaogu")
    yield
    print("haoshuai")


with func():  # 执行此处时,xiaogu会首先输出,3秒后haoshuai继续输出
    time.sleep(3)
    pass

输出:
xiaogu
haoshuai

在以上代码中,通过装饰器的形式实现上下文管理器,这种方式只需要定义一个函数,加上contextmanager装饰器即可,在函数中使用yield关键字,在yield以上的内容相当于是在__enter__()方法中执行,yield后边的值为返回值,如果没有则说明没有返回值,yield以后的代码相当于__exit__()方法中执行

发布了36 篇原创文章 · 获赞 2 · 访问量 931

猜你喜欢

转载自blog.csdn.net/zzrs_xssh/article/details/104583138