【问题标题】:Python context manager for opening file catching FileNotFound error [closed]用于打开文件捕获 FileNotFound 错误的 Python 上下文管理器
【发布时间】:2023-01-28 00:27:30
【问题描述】:

我已经尝试编写一个 Python 上下文管理器,它可以安全地打开文件进行读取并优雅地处理 FileNotFound 错误。这是我的代码:

filename = 'my_file.txt'

class SafeRead:

    def __init__(self,fname):
        self.filename = fname

    def __enter__(self):
        try:
            self.file_handle = open(self.filename,'r')
        except Exception as e:
            self.file_handle = None
            print(e)
        return self.file_handle

    def __exit__(self,e_type,e_val,e_trace):
        if self.file_handle:
            self.file_handle.close()

with SafeRead(filename) as f:
    if f: data = f.read()

但是,我觉得结果很笨拙,尤其是对正文中的文件对象进行了额外的测试,以在尝试访问未定义的文件句柄时抑制额外的异常。有没有更好的办法?

【问题讨论】:

  • 它有效吗? Code Review
  • 您如何处理此异常没有什么优雅之处。您刚刚将处理异常的需要替换为检查f 的值的需要。这是较少的比以前安全。
  • 真正“安全”的读取将提供一个合适的类文件对象来代替None。也许 f.read() 返回一个空字符串,但也许 my_file.txt 也是如此。
  • 谢谢 @chepner 缺少 if f: 子句并且无法弄清楚它是如何工作的:您刚刚将处理异常的需要替换为检查 f 的值的需要。这比以前更不安全

标签: python error-handling


【解决方案1】:

您的代码可以使用 contextlib.contextmanager 装饰器进行简化。

from contextlib import contextmanager

@contextmanager
def SafeRead(filename):
    try:
        file_handle = open(filename, 'r')
        yield file_handle
        file_handle.close()
    except FileNotFoundError as e:
        print(e)
        yield None

filename = 'test.txt'

with SafeRead(filename) as f:
    if f: data = f.read()

至于不用检查返回文件句柄的值,我觉得没有resorting to black magic是做不到的。

【讨论】:

    【解决方案2】:

    在这种情况下,“安全”通常意味着即使您不能返回您想要返回的内容,您也可以返回足够相似的内容,以便您的代码在任何一种情况下都可以继续。您可以做的最简单的事情就是返回一个您仍然可以读取的类似文件的对象。什么你从那个对象中读取取决于情况,所以你也可以让调用者提供一个合适的值,以防文件无法访问。例如,

    from io import StringIO
    
    class SafeRead:
    
        def __init__(self, fname, data=""):
            self.filename = fname
            self.backup = data
    
        def __enter__(self):
            try:
                self.file_handle = open(self.filename,'r')
            except Exception as e:
                self.file_handle = StringIO(self.backup)
            return self.file_handle
    
        def __exit__(self,e_type,e_val,e_trace):
            self.file_handle.close()
    
    
    with SafeRead(filename, "foobar") as f:
        assert os.path.exists(filename) or f.read() == "foobar"
    

    【讨论】:

      猜你喜欢
      • 2015-05-10
      • 1970-01-01
      • 2020-04-02
      • 1970-01-01
      • 1970-01-01
      • 2013-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多