cdr对象管理器怎么用_叮咚,我精心帮你总结了Python with上下文管理器的知识点,请查收!...

正好前几天有小伙伴在「测试开发群」里问「Python上下文管理器」有哪些使用场景。我感觉多数人应该经常用,但是换了个问法后就有点陌生了,所以我花点时间给大家整理下Python上下文管理器的知识点。

读写文件常规写法

在Python中,读写文件我们经常用下面这种写法:

with open("test_file.txt", "w+") as test_file:
  print(test_file)
  test_file.write("hello world")

这里其实就用到了with上下文管理器。它的工作原理是什么呢?

我们从代码字面意思可以猜到with open……语句返回的是一个操作文件的句柄对象(打印出来的值是:)。

然后我们直接使用这个TextIoWrapper进行文件的读写,但是还有个奇怪的问题,为什么用完test_file之后,我们不需要手动调用test_file.close()方法来关闭对象呢?

难道是系统会自动帮我们关闭IO对象吗?

追根溯源

好在Python是开源的,我们可以查看它的源码来验证我们的想法,在Pycharm中,直接点进去查看open方法的源码,但是却是个空实现,那真实的逻辑在哪里呢?

因为Python默认使用的是CPython,因此肯定有地方是能找到源码的,经过搜索,发现Python的源码就在github上放着。怎么找到对应的源码呢?

可以直接使用关键字搜索,我是用Pycharm中看到的方法注释「Open file and return a stream」,结果搜索出很多相关的代码段,github这个搜索功能貌似会将搜索语句分割成一个个关键字。没办法只能硬着头皮翻看头几页。

bingo!!找到如下图所示的内容:

c2c5a3f2ea1817156d835472bcc2ef9a.png

其中一个是文件读写的C语言实现方式,另一个是py实现。我们就从py实现开始看,说不定就能找到我们需要的内容。还记得上面with open方法返回的是一个TextIOWrapper对象吧,我们直接在文件中搜索:「TextIOWrapper」,还真找到了,如下图所示:

4304be86de8fdbf859f8da2b3d5fa1ac.png

接下来,我们需要找到它在哪里调用了close之类的方法来关闭文件读写的句柄。在TextIOWrapper类中,没找到有相关的操作,只能到它的父类TextIOBase中找找看。

在TextIOBase中只有常规的读和写的空实现,没找到我们需要的东西。只能再查看它的父类:IOBase,如果再找不到只能去C代码中碰碰运气。

功夫不负有心人啊,在IOBase中,我们看到了我们想找的代码,如下所示:

fe199cd5f3fee91732b35488eb0938a7.png

这个enter和exit方法又是怎么回事呢?网上查了下,它们和Python With上下文管理器有关系。所谓的上下文管理器是用来执行with语句时建立的运行时上下文的一个对象,通过调用对象的__ enter _「和_」 exit __ 方法来实现。

自定义一个With上下文管理器

了解完Python的With上下文管理器怎么使用,接下来我们就尝试自己动手写一个上下文管理器,加深大家对它的理解。我们直接定义一个有异常情况发生的代码:

class TestWith(object):
    def __init__(self):
        print("初始化")

    def __enter__(self):
        print("enter")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("exit")
        print(exc_type)
        print(exc_val)
        print(exc_tb)
        return True

    def operation(self):
        print('todo something')
        print(1 / 0)
        print('exception happened')


if __name__ == '__main__':
    # # 使用自定义的上下文管理器
    with TestWith() as f:
        f.operation()

执行上面代码的结果如下所示:

初始化
enter
todo something
exit
<class 'ZeroDivisionError'>division by zero
<traceback object at 0x109bdcbe0>

奇怪了,为什么没有抛出异常,我们代码中明明使用了1/0。这就是上下文管理器高明的地方,它能对异常进行捕获处理。可以注意到__exit__方法有三个参数:exc_type, exc_val,exc_tb,它们分别表示:

  • exc_type:异常类型
  • exc_val:异常值
  • exc_tb:异常的堆栈信息

在上面例子中,它返回的值是就是等,不过需要注意当我们程序主逻辑没有报错时,这三个参数将都返回None。

python上下文管理器的优势

我总结了我认为的几个优势:

  • 它能让我们的代码变的简洁,比如:with open读写文件时,我们不需要再去调用close方法,避免遗忘造成的各种问题。
  • 它能对异常进行捕获处理,其实也是让代码简洁了,我们不需要在代码中写很多try...except。
  • 它能提高代码的复用率,比如:我们可以将一些常用的操作放到init(初始化操作)和exit(退出操作)方法中,这样方便其他人调用。

常驻小尾巴:欢迎加我的个人微信:xuanke_721,我拉大家加入测试开发群,和全国的测试小伙伴一起交流沟通!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值