在这种情况下如何防止"too broad exception"?

How to prevent "too broad exception" in this case?

我有一个可能失败的函数列表,如果有一个失败,我不希望脚本停止,而是继续执行下一个函数。

我正在用这样的东西执行它:

list_of_functions = [f_a, f_b, f_c]
for current_function in list_of_functions:
    try:
        current_function()
    except Exception:
        print(traceback.format_exc())

工作正常,但不符合 PEP8:

When catching exceptions, mention specific exceptions whenever possible instead of using a bare except: clause.

For example, use:

try:
    import platform_specific_module
except ImportError:
    platform_specific_module = None

A bare except: clause will catch SystemExit and KeyboardInterrupt exceptions, making it harder to interrupt a program with Control-C, and can disguise other problems. If you want to catch all exceptions that signal program errors, use except Exception: (bare except is equivalent to except BaseException: ).

A good rule of thumb is to limit use of bare 'except' clauses to two cases:

If the exception handler will be printing out or logging the traceback; at least the user will be aware that an error has occurred.

If the code needs to do some cleanup work, but then lets the exception propagate upwards with raise . try...finally can be a better way to handle this case.

我怎样才能做到这一点?

您引用的 PEP8 指南建议在您的情况下使用裸异常是可以的,前提是您要记录错误。我认为你应该涵盖尽可能多的异常,因为你 can/know 如何处理,然后记录其余的和 pass,例如

import logging

list_of_functions = [f_a,f_b,f_c]
for current_function in list_of_functions:
    try:
        current_function()
    except KnownException:
        raise
    except Exception as e:
        logging.exception(e)

您的意思是每个函数都可以引发不同的异常?当您在 except 子句中命名异常类型时,它可以是引用异常的任何名称,而不仅仅是 class 名称。

例如

def raise_value_error():
    raise ValueError

def raise_type_error():
    raise TypeError

def raise_index_error():
    doesnt_exist

func_and_exceptions = [(raise_value_error, ValueError), (raise_type_error, TypeError), 
    (raise_index_error, IndexError)]

for function, possible_exception in func_and_exceptions:
   try:
       function()
   except possible_exception as e:
       print("caught", repr(e), "when calling", function.__name__)

打印:

caught ValueError() when calling raise_value_error
caught TypeError() when calling raise_type_error
Traceback (most recent call last):
  File "run.py", line 14, in <module>
    function()
  File "run.py", line 8, in raise_index_error
    doesnt_exist
NameError: name 'doesnt_exist' is not defined

当然,这让您在每次发生异常时都不知道该怎么办。但是既然你只是想忽略它并继续那么这不是问题。

issue PY-9715 到 yourtrack.jetbrains.com:

来自pep-0348

BaseException

The superclass that all exceptions must inherit from. It's name was chosen to reflect that it is at the base of the exception hierarchy while being an exception itself. "Raisable" was considered as a name, it was passed on because its name did not properly reflect the fact that it is an exception itself.

Direct inheritance of BaseException is not expected, and will be discouraged for the general case. Most user-defined exceptions should inherit from Exception instead. This allows catching Exception to continue to work in the common case of catching all exceptions that should be caught. Direct inheritance of BaseException should only be done in cases where an entirely new category of exception is desired.

But, for cases where all exceptions should be caught blindly, except BaseException will work.

我认为在一些罕见的情况下捕获一般异常是合理的,并且有一种方法可以欺骗 PEP8 检查:

list_of_functions = [f_a,f_b,f_c]
for current_function in list_of_functions:
try:
    current_function()
except (ValueError, Exception):
    print(traceback.format_exc())

您可以将 ValueError 替换为任何其他内容。它对我有用(至少在 PyCharm)。

如果您随后重新引发异常,则可以避免该错误。这样您就可以进行损害控制,而不会危及失去对其发生的跟踪。

你可以像 except Exception as error: # pylint: disable=broad-except 这样的评论,这实际上对我有用。希望对你有用。

用这个来欺骗 PEP8:

try:
    """code"""

except (Exception,): 
    pass

首先,使用以下命令生成pylintrc

pylint --generate-rcfile > .pylintrc

供参考: https://docs.microsoft.com/en-us/visualstudio/python/linting-python-code?view=vs-2022

在生成的 pylintrc 文件中搜索禁用(如果需要则取消注释)并添加以下异常。

broad-except

重新运行 pylint 命令,看看神奇之处