Python 中 open() 方法既能直接返回也能通过with语句当作上下文管理器使用是怎么做到的?

php中文网
发布: 2016-06-06 16:24:09
原创
1310人浏览过

如题。简单看了下io.py部分的源码,只看到了open的定义是直接返回对象,没有看到是如何实现上下文管理器的。Google了半天也没有结果。求知乎大神解答!

BlessAI
BlessAI

Bless AI 提供五个独特的功能:每日问候、庆祝问候、祝福、祷告和名言的文本生成和图片生成。

BlessAI 89
查看详情 BlessAI

回复内容:

前段时间果壳 Python 开发面试被问到了这个问题

实现某个对象可以用 with 来管理,只需要改写 __enter__ 和 __exit__ 这两个 magic method 即可

另外你说你在 io.py 源码里没找到,大哥读代码要仔细啊

io.py 里的 IO 函数都是从 _pyio.py 里 import 进来的,然后在 _pyio.py 的第 140 行 到 147 行有这么一段注释

open() returns a file object whose type depends on the mode, andthrough which the standard file operations such as reading and writingare performed. When open() is used to open a file in a text mode ('w','r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to opena file in a binary mode, the returned class varies: in read binarymode, it returns a BufferedReader; in write binary and append binarymodes, it returns a BufferedWriter, and in read/write mode, it returnsa BufferedRandom.

所以 open() 这个函数在不同模式下会返回不同的对象,包括 TextIOWrapper/BufferedReader/BufferedWriter 这三种

继续看上面这三个类的定义,发现这几个类还继承了其他的几个类,这里我就不领着你看了,直接用 Visio 画了个类层次示意图,如下

Python 中 open() 方法既能直接返回也能通过with语句当作上下文管理器使用是怎么做到的?
其中蓝色矩形表示 class,蓝色连线表示继承关系,蓝色连线上的数字表示这个继承关系的代码在源码中的哪一行

可以看到 open() 函数所返回的几个 class,最终都继承于 IOBase 这个 class,而在这个 class 中,就实现了 __enter__() 和 __exit() 两个 magic method,具体代码位于 _pyio.py 的第 428 行到 437 行

<code class="python">    <span class="c">### Context manager ###</span>

    <span class="k">def</span> <span class="nf">__enter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">"""Context management protocol.  Returns self."""</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_checkClosed</span><span class="p">()</span>
        <span class="k">return</span> <span class="bp">self</span>

    <span class="k">def</span> <span class="nf">__exit__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">):</span>
        <span class="sd">"""Context management protocol.  Calls close()"""</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</code>
登录后复制
只要有__enter__和__exit__方法,就能用在with语句里,open返回的对象有这两个方法,就可以了,不必在open方法内做什么手脚。 Python 的上线文管理器使用with关键字,用来定义with后面这个缩进级别,进入和跳出的行为,是语法糖的一种。open是一个调用用于实例化file类的函数,而file类只不过是一个拥有__enter__和__exit__(这种前后都有两个下划线的在Python中叫做“魔法方法”,除了这两个还有很多,有兴趣可以去查一下)的类,用在with中时,程序会自动在进出这个程序块时调用这两个函数,如果没用with就要手动管理,自己调用close()。如果想要自己实现类似的功能,用回调就,或者单独封装成装饰器(装饰器其实也是Python的一种语法糖)都可以。 跟Java的Closeable一样 定义好释放资源的方式 通过语法糖隐藏部分重复代码 你google context manager就有结果了
相关标签:
python速学教程(入门到精通)
python速学教程(入门到精通)

python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号