上下文管理器:__init__ 方法内的错误处理

alf*_*oSR 5 python contextmanager

一些背景

我正在使用一个包,它允许您使用文件中存储的信息来计算有关行星的一些信息(例如它们的速度或位置)。该包包含加载和卸载文件的方法,因此其基本用法如下所示:

load(["File_1", "File_2"])

try:

    function()

finally:

    unload(["File_1", "File_2"])
Run Code Online (Sandbox Code Playgroud)

由于这是上下文管理器实用程序的教科书示例,并且该包缺少一个,因此我正在编写自己的示例。

class file_manager:

    def __init__(self, file_list) -> None:

        self.file_list = file_list

        load(self.file_list)

        return None

    def __enter__(self) -> None:

        return None

    def __exit__(self, exc_type, exc_value, traceback) -> None:

        unload(self.file_list)

        return None
Run Code Online (Sandbox Code Playgroud)

使用新的上下文管理器,前面的示例可以重写如下:

with file_manager(["File_1", "File_2"]):

    function()
Run Code Online (Sandbox Code Playgroud)

该方法保证如果出现错误__exit__,文件仍然会被卸载。function

我的问题

load函数逐个加载文件,而不首先检查所有文件是否可用。因此,如果File_1存在,但File_2不存在,File_1则会被加载,并且在加载时会引发异常File_2。根据 python 文档:

with 语句保证如果__enter__()方法返回且没有错误,则__exit__()始终会调用 then。

因此,在前面的情况下,程序的执行将在没有File_2被卸载的情况下结束。

我在寻找什么

我显然可以通过try...except在方法中使用一个子句来解决这个问题__init__()

def __init__(self, file_list) -> None:

    self.file_list = file_list

    try:

        load(self.file_list)

    except FileDoesNotExistError:

        self.__exit__(FileDoesNotExistError, False, None)
Run Code Online (Sandbox Code Playgroud)

但我想知道这是否是解决这个问题的正确方法。例如,在 Cython 中,类有一个__dealloc__()方法,无论发生什么类型的异常,该方法都保证运行。

che*_*ods 4

您可以使用 包装原始代码contextlib.contextmanager

from contextlib import contextmanager

@contextmanager
def file_manager(file_list):
    try:
        load(file_list)
        yield None  # after this the code inside the with block is executed 
    finally:
        # this is called when the with block has finished
        # or when load raises an exception
        unload(file_list)
Run Code Online (Sandbox Code Playgroud)

并像这样使用它

with file_manager(["File_1", "File_2"]):
    function()
Run Code Online (Sandbox Code Playgroud)