open 如何处理上下文管理?
How does open handle context management?
python 内置函数 open
和 file
以我不太理解的方式与上下文管理器一起工作。
据我了解,open
将创建一个 file
。 file
实现上下文管理器方法 __enter__
和 __exit__
。我最初希望 __enter__
实现文件描述符的实际打开。
但是,在 with
块之外使用 open
将 return 一个已经打开的 file
。因此,似乎 file.__init__
或 open
实际上正在打开文件描述符,据我所知 file.__enter__
没有做任何事情。或者 file.__init__
/open
直接调用 file.__enter__
?
第一个问题:
open
内置的执行流程是什么? open
处理什么,file.__init__
处理什么,file.__enter__
处理什么?在 opening/closing 文件的多个循环中重复使用一个 file
对象时,这是如何工作的?这与为多个上下文循环重复使用其他上下文管理器对象有何不同?
第二个问题:
像file
这样的对象有设置步骤和拆卸步骤。设置发生在 __init__
中,拆卸发生在 close
或 __exit__
.
中
这是一个好的设计模式吗?是否应为自定义 functions/context 经理实施此设计模式?
如果您查看 _pyio.py(io 模块的 pure-Python 实现),您会在 class 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__
处理什么?没有什么。它只是 returns 文件对象,它是调用 built-in 函数 open() 的结果。
当使用一个文件对象多次打开和关闭文件时,这是如何工作的?上下文管理器对此用途不是很有用,因为您每次都必须显式打开文件。
这是一个好的设计模式吗?是的,因为它减少了您必须编写的代码量,因此易于阅读和理解。
是否应该为自定义 functions/context 经理实施此模式?任何时候你有一个对象需要清理,或者使用涉及某种类型的 open/close 概念,你应该考虑这个模式。标准库还有许多其他示例。
对于问题 1
在 CPython 中,open() 除了创建一个 file 对象外什么都不做,底层 C 类型是PyFileObject;请参阅 bltinmodule.c and 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 上引入的两个不同的关键字。 with 被引入到 Python 2.5(参见 PEP 343)。当时open已经用了很久
对于我们自定义的类型,我们可以像file那样设计,也可以不这样,要看具体的应用上下文。
比如threading.Lock就是不同的设计,它的init和enter 是分开的。
python 内置函数 open
和 file
以我不太理解的方式与上下文管理器一起工作。
据我了解,open
将创建一个 file
。 file
实现上下文管理器方法 __enter__
和 __exit__
。我最初希望 __enter__
实现文件描述符的实际打开。
但是,在 with
块之外使用 open
将 return 一个已经打开的 file
。因此,似乎 file.__init__
或 open
实际上正在打开文件描述符,据我所知 file.__enter__
没有做任何事情。或者 file.__init__
/open
直接调用 file.__enter__
?
第一个问题:
open
内置的执行流程是什么? open
处理什么,file.__init__
处理什么,file.__enter__
处理什么?在 opening/closing 文件的多个循环中重复使用一个 file
对象时,这是如何工作的?这与为多个上下文循环重复使用其他上下文管理器对象有何不同?
第二个问题:
像file
这样的对象有设置步骤和拆卸步骤。设置发生在 __init__
中,拆卸发生在 close
或 __exit__
.
这是一个好的设计模式吗?是否应为自定义 functions/context 经理实施此设计模式?
如果您查看 _pyio.py(io 模块的 pure-Python 实现),您会在 class 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__
处理什么?没有什么。它只是 returns 文件对象,它是调用 built-in 函数 open() 的结果。
当使用一个文件对象多次打开和关闭文件时,这是如何工作的?上下文管理器对此用途不是很有用,因为您每次都必须显式打开文件。
这是一个好的设计模式吗?是的,因为它减少了您必须编写的代码量,因此易于阅读和理解。
是否应该为自定义 functions/context 经理实施此模式?任何时候你有一个对象需要清理,或者使用涉及某种类型的 open/close 概念,你应该考虑这个模式。标准库还有许多其他示例。
对于问题 1
在 CPython 中,open() 除了创建一个 file 对象外什么都不做,底层 C 类型是PyFileObject;请参阅 bltinmodule.c and 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 上引入的两个不同的关键字。 with 被引入到 Python 2.5(参见 PEP 343)。当时open已经用了很久
对于我们自定义的类型,我们可以像file那样设计,也可以不这样,要看具体的应用上下文。
比如threading.Lock就是不同的设计,它的init和enter 是分开的。