在引发错误和记录错误之间,在 Python 中哪个是更好的做法?

Smi*_* Lo 3 python

Python 教程有一个名为 Errors and Exceptions 的部分,它使用结构作为;

try:
    [statement]
except [Built-in ExceptionType]:
    do something when an exception has been captured.
finally:
    do something whether exception occurred or not.
Run Code Online (Sandbox Code Playgroud)

这也可以通过直接引发错误来处理。

try:
    raise [Built-in ExceptionType]
except [Built-in ExceptionType above] as e:
    print(f'foo error: {e}')
Run Code Online (Sandbox Code Playgroud)

有几个内置的 ExceptionType,良好的做法是开发人员应该捕获开发人员应该寻找的每个特定异常类型。(请参阅为什么“除了:通过”是一种糟糕的编程习惯?

但是,在我阅读日志部分之后。我在想我想将错误记录到日志文件中,让用户知道错误(也许只是打印文本,用户可以通知 IT 支持),而不是在屏幕上抛出异常。因此,代替上面的 try / except 组合,我可以使用以下错误消息并记录下来。

if len(symbol) != 1:
    error_message = f'Created box with symbol={symbol}, width={width} and height={height}, Symbol needs to be a string of length 1'
    logger.error(error_message)
    print(f'\nError! symbol={symbol}, width={width} and height={height} -- Symbol needs to be a string of length 1')
    return
Run Code Online (Sandbox Code Playgroud)

我怀疑目前更好的做法是:

a) 在屏幕上引发错误和

b) 记录错误以进行进一步调查?

c)其他方法(请建议我)

我希望我不要试图比较两个不同的东西。对我来说,我想选择 b) 并将错误存储在日志中。这更易于调查,并且不会向用户提供不必要的信息。但我不确定我是否在正确的轨道上。非常感谢。

dec*_*eze 6

记录和引发异常两种不同的事情,有两个不同的目的。日志可以让您检查程序在事后做了什么。引发异常现在对程序流程有重要影响。有时你想要其中之一,有时你想要另一个,有时你两者都想要。

问题始终是错误是预期的还是意外的,您是否有计划在发生错误时该怎么做,以及通知任何人错误的发生是否有用。

您有“备份计划”的预期错误应该被捕获和处理,这是常规的程序控制流。意外错误可能应该停止程序,或者至少停止发生错误的特定函数。如果更高层的调用者想要处理异常,那就让他们处理吧。是否记录错误(除了处理或不处理错误之外)取决于是否有人可以从该日志条目中收集任何有用的见解,或者它是否只是噪音。


bru*_*ers 5

正如 deceze 已经提到的,日志记录和异常是两个完全不同的东西。作为基本规则:

  • 当您遇到在代码的这一点无法处理的意外/无效情况时,您会引发异常。这个异常会变成什么(调用堆栈中的某个人是否会处理它)此时与您无关

  • 只有当您可以处理它或想要记录它(最终带有附加上下文信息)时,您才会捕获异常,然后重新提出它

  • 在您的应用程序的顶层,您最终会添加一个包罗万象的异常处理程序,它可以记录异常并根据应用程序的类型(命令行脚本、GUI 应用程序、网络服务器等)决定处理这种情况的最佳方式...... )。

日志记录主要是用于事后检查、程序行为分析等的开发人员/管理工具,它既不是错误处理工具,也不是最终用户 UI 功能。你的例子:

if len(symbol) != 1:
    error_message = f'Created box with symbol={symbol}, width={width} and height={height}, Symbol needs to be a string of length 1'
    logger.error(error_message)
    print(f'\nError! symbol={symbol}, width={width} and height={height} -- Symbol needs to be a string of length 1')
    return
Run Code Online (Sandbox Code Playgroud)

是一个完美的反模式。如果您的函数需要一个字符串并且调用者传递了其他任何内容,那么唯一合理的解决方案是引发异常并让调用者处理它。再一次,它是如何做到的,这与您无关。


Bij*_*dra 1

来自文档

Returns a new instance of the SMTPHandler class. The instance is initialized with the from and to addresses and subject line of the email. The toaddrs should be a list of strings. 
Run Code Online (Sandbox Code Playgroud)

logging.handlers.SMTPHandler可用于发送记录的错误消息。

    import logging
    import logging.handlers

    smtp_handler = logging.handlers.SMTPHandler(mailhost=("example.com", 25),
                                        fromaddr="from@example.com", 
                                        toaddrs="to@example.com",
                                        subject="Exception notification")
    logger = logging.getLogger()
    logger.addHandler(smtp_handler)
Run Code Online (Sandbox Code Playgroud)

如果需要停止代码执行,您可以在此处中断逻辑。

另请查看我之前提到的这个答案collat​​e-output-in-python-logging-memoryhandler-with-smtphandler