python内置插件open
和file
以一种我不太了解的方式与上下文管理器一起工作。
根据我的理解,open
将创造一个file
。 file
实现了上下文管理器方法__enter__
和__exit__
。我最初希望__enter__
实现文件描述符的实际打开。
但是,在open
区块之外使用with
将返回已经打开的file
。所以,看来file.__init__
或open
实际上是打开文件描述符,据我所知,file.__enter__
没有做任何事情。或者也许file.__init__
/ open
直接打电话给file.__enter__
?
第一个问题:
open
内置的执行流程是什么? open
处理什么,file.__init__
处理什么,以及file.__enter__
处理什么?当重复使用一个file
对象打开/关闭文件的多个循环时,这是如何工作的?这与为多个上下文循环重用其他上下文管理器对象有何不同?
第二个问题:
诸如file
对象之类的对象具有设置步骤和拆除步骤。设置发生在__init__
,并且拆除发生在close
或__exit__
。
这是一个很好的设计模式吗?是否应该为自定义函数/上下文管理器实现此设计模式?
如果查看_pyio.py(io模块的纯Python实现),可以在类IOBase中找到以下代码:
### Context manager ###
def __enter__(self): # That's a forward reference
"""Context management protocol. Returns self (an instance of IOBase)."""
self._checkClosed()
return self
def __exit__(self, *args):
"""Context management protocol. Calls close()"""
self.close()
这包含大多数问题的答案。需要了解的重要一点是,上下文管理器的功能是确保在完成文件后关闭文件。它只需调用close
函数即可完成此操作,这样可以省去这样做的麻烦。
file.__enter__
处理什么?没有。它只是返回文件对象,该文件对象是对内置函数open()的调用的结果。
在打开和关闭文件的多个循环中使用一个文件对象时,这是如何工作的?上下文管理器对此目的不是很有用,因为每次都必须显式打开文件。
这是一个很好的设计模式吗?是的,因为它减少了你必须编写的代码量,所以它易于阅读和理解。
是否应该为自定义函数/上下文管理器实现此模式?每当你有一个需要清理的对象,或者有一些涉及某种开/关概念的用法时,你应该考虑这种模式。标准库还有许多其他示例。
问题1
在CPython中,open()除了创建一个文件对象之外什么都不做,底层C类型是PyFileObject;请参阅bltinmodule.c和fileobject.c中的源代码
static PyObject *
builtin_open(PyObject *self, PyObject *args, PyObject *kwds)
{
return PyObject_Call((PyObject*)&PyFile_Type, args, kwds);
}
file.__init__
会打开文件file.__enter__
确实什么都不做,除了对file.fp
场进行空检查file.__exit__
调用close()
方法来关闭文件问题2
为什么file
这样的设计是由于历史原因。
open和with是在不同版本的CPython上引入的两个不同的关键字。随着Python 2.5的推出(见PEP 343)。那时,open已经使用了很长时间。
对于我们的自定义类型,我们可以设计像文件一样,取决于具体的应用程序上下文。
例如,threading.Lock是一个不同的设计,它的init和enter是分开的。