在资源不可用时有效处理 __enter__ 引发的 python 异常

Effectively handling python exceptions raised from __enter__ when resource is unavailable

我想通过 with 管理资源,但是当此资源不可用时我无法处理异常。我的资源是一种 FileLock 机制,可避免在将输出写入 csv 文件时并行处理 运行 之间的冲突。我的代码是这样写的:

data_not_to_lost  # this is a dataframe
with FileLock('database.csv'):
    data_not_to_lost.to_csv('database.csv')

我遇到的问题是有时资源不可用。发生这种情况时,FileLock 会从其 __enter__ 方法中引发异常。这使得 with 块内的主要代码没有被执行(据我所知, __exit__ 方法也没有被调用)。

我对这个问题的解决方案是将整个环境包裹在 try...except 对中,如下所示:

    data_not_to_lost  # this is a dataframe
    try:
        with FileLock('database.csv'):
            data_not_to_lost.to_csv('database.csv')
    except FileLockException:
        data_not_to_lost.to_csv('backup.csv')

这个解决方案似乎可行,但它读起来很难看,而且很可能是反模式,因为:

  1. with 中的代码(在我的实际实现中更大)必须在两个不同的部分重复,因此很容易出现错误。
  2. 我了解到 with 的很多内容是为了避免在多个级别链接 try ... except 子句。目前我需要两个级别(这在某种程度上很烦人,因为我的代码已经非常缩进并且每行坚持 80 个字符变得很痛苦)。

我错过了什么吗?我的“解决方案”是处理资源不可用时引发的异常的正确方法吗?

I had understood that a great deal about with is to avoid chaining try ... except clauses at multiple levels.

不是我的理解,我从未听过或读过这是上下文管理器的内在功能。他们的目的是管理资源。
PyMOTW 说得好:

A context manager is responsible for a resource within a code block, possibly creating it when the block is entered and then cleaning it up after the block is exited.

FileLock 管理的资源是锁定文件,以确保对文件的独占访问。当您无法获得独占访问权限时,它可以 'tell',但处理此类情况取决于您。
你可以尝试在 FileLock 上增加 timeout,但最终你需要一个在尝试获取锁时超时的策略。

The code inside the with (which in my actual implementation is larger) has to be repeated in two different parts, therefore being a magnet for bugs.

我知道你问题中的代码只是一个精简的例子,但如果你理所当然地不愿意重复代码部分,是否没有机会将它移动到一个你可以参数化的函数,具体取决于锁是否能不能获得?

def do_stuff(filename):
    data_not_to_lost.to_csv(filename)

try:
    with FileLock('database.csv'):
        do_stuff('database.csv')
except FileLockException:
    do_stuff('backup.csv')