如何打开句柄上下文管理?

时间:2018-03-06 01:35:36

标签: python file with-statement contextmanager

python内置插件openfile以一种我不太了解的方式与上下文管理器一起工作。

据我了解,open会创建一个filefile实现了上下文管理器方法__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__

这是一个好的设计模式吗?是否应该为自定义函数/上下文管理器实现此设计模式?

2 个答案:

答案 0 :(得分:2)

如果你查看_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 :(得分:1)

问题1

在CPython中, open()除了创建文件对象外,其他基础C类型为 PyFileObject ;请参阅bltinmodule.cfileobject.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这样设计是由于历史原因。

打开是在不同版本的CPython上引入的两个不同的关键字。在Python 2.5中引入了 with (参见PEP 343)。那时,打开已经使用了很长时间。

对于我们的自定义类型,我们可以设计为文件,具体取决于具体的应用程序上下文。

例如, threading.Lock 是一种不同的设计,其 init 输入是分开的。