上下文管理器的“打开工作”应该发生在 __init__ 还是 __enter__ 中?

Bee*_*ope 2 python contextmanager

我找到了下面的例子以下对象上下文管理器的File

\n
class File(object):\n    def __init__(self, file_name, method):\n        self.file_obj = open(file_name, method)\n    def __enter__(self):\n        return self.file_obj\n    def __exit__(self, type, value, traceback):\n        self.file_obj.close()\n
Run Code Online (Sandbox Code Playgroud)\n

在这里,管理器完成的工作(实际上是打开文件)发生在该__init__方法中。然而,在随附的文本中,他们建议文件打开应该发生在__enter__

\n
\n

让\xe2\x80\x99s 谈谈幕后发生的事情。

\n
    \n
  1. with 语句存储退出File类的
  2. \n
  3. 它调用输入File 类的
  4. \n
  5. 进入打开文件并返回它。
  6. \n
  7. 打开的文件句柄被传递给opened_file。
  8. \n
  9. 我们使用 .write() 写入文件。
  10. \n
  11. with 语句调用存储的退出方法。
  12. \n
  13. 出口关闭文件。
  14. \n
\n
\n

一般来说,哪种方法是正确的?似乎撤销的工作__exit__应该发生在__enter__,而不是__init__因为它们是通过上下文管理器机制 1:1 配对的,但这个例子让我感到怀疑。

\n

use*_*ica 6

没有一般性的答案。这取决于工作什么。例如,对于文件,打开发生在__init__,但对于锁,锁定发生在__enter__

需要考虑的一件重要事情是,如果对象不用作上下文管理器,或者不立即用作上下文管理器,会发生什么情况?构建后对象的状态应该是什么?那时是否应该已经获得相关资源?

对于文件,答案是肯定的,该文件应该已经打开,因此打开发生在__init__. 对于锁来说,答案是否定的,锁不应该被锁,所以锁就进去了__enter__

另一件需要考虑的事情是,这个对象是否可以多次用作上下文管理器?如果进入上下文管理器两次应该做两次某件事,那么该事情需要在__enter__.

  • @MadPhysicist:这是一种冗长的说法,“这需要根据具体情况来决定”,而不是“这是一个意见问题”。 (3认同)