【问题标题】:Should I close a stream (file-like object) passed into my object in the context manager __exit__() function?我应该关闭在上下文管理器 __exit__() 函数中传递给我的对象的流(类文件对象)吗?
【发布时间】:2013-07-03 14:33:56
【问题描述】:

我有一个对象,我希望能够在其上使用 with 关键字。我对实现上下文管理器的实用性感到满意,但我正在努力解决最佳实践类型的问题。

对象是文件的包装器。我计划用字符串(文件的路径)或可以直接处理的类似文件来初始化我的对象(文件中有文件的可能性 - 所以我预见到一个明确的用例这与 BytesIO 等...)

所以__init__看起来像这样:

def __init__(self, file_to_process):
    if isinstance(file_to_process, str):
        self._underlying_stream = open(file_to_process, "rb") # it's the path to a file
    elif isinstance(file_to_process, io.IOBase):
        self._underlying_stream = file_to_process # its the file itself
    else:
         raise TypeError()

所以我的问题是,在我的 __exit__() 函数中关闭 _underlying_stream 是最佳做法/可接受/明智吗?当它是一条路径时,这完全是有道理的,但如果它是一条流进来的,我觉得关闭self._underlying_stream 充其量是不礼貌的,最坏的情况是危险的 - 我这样想是否正确,如果是这样,有没有解决这个问题的好方法?

(注意:我考虑用io.BufferedReader 包装进来的流,但结果证明关闭也会关闭底层流...)

【问题讨论】:

  • 最简单的方法是在测试字符串实例时设置self._close_on_exit = True
  • 取决于上下文,但对于现有打开的流,我可能会保持打开状态,然后调用者可以选择是否要在之后关闭它。正如 Steven 建议的那样,您可以使用另一个变量来记住是否需要关闭流。无论您决定采用哪种方式,请确保行为有据可查。
  • 是的,你可能是对的,我考虑过这一点,但感觉太简单了,就像我错过了一些聪明的东西。但我怀疑,像往常一样,简单优于复杂......
  • 如果您愿意,您可以按照def __init__(self, file_to_process, always_close_stream=False) 的行向您的方法添加一个关键字arg,如果调用者希望关闭流,则可以将其显式设置为True

标签: python file stream contextmanager


【解决方案1】:

不会关闭底层流。传入一个已经打开的文件对象意味着调用者已经对该对象负责并且在__exit__上关闭该对象充其量是非常烦人的。

PIL 做了类似的事情,尽管不在上下文管理器中。传入文件名时,它会在完成读取图像数据后关闭文件对象。它为此设置了一个布尔标志。而是传入一个文件对象,它会读取但不会关闭。

我也会在这里做同样的事情:

class Foo(object):
    _close_on_exit = False

    def __init__(self, file_to_process):
        if isinstance(file_to_process, str):
            self._underlying_stream = open(file_to_process, "rb") # it's the path to a file
            self._close_on_exit = True
        elif isinstance(file_to_process, io.IOBase):
            self._underlying_stream = file_to_process # its the file itself
        else:
             raise TypeError()

    def __exit__(self, exc_type, exc_value, traceback):
        if self._close_on_exit:
            self._underlying_stream.close()

【讨论】:

  • 简单胜于复杂。
猜你喜欢
  • 1970-01-01
  • 2021-03-20
  • 2021-08-26
  • 2020-07-29
  • 2017-04-08
  • 2011-10-06
  • 1970-01-01
  • 1970-01-01
  • 2011-06-04
相关资源
最近更新 更多