【问题标题】:How to print an exception when I'm not handling it?当我不处理异常时如何打印它?
【发布时间】:2018-02-21 09:51:40
【问题描述】:

我有以下代码:

# exc is a local variable of type Exception
# This is not inside an except block
if isinstance(exc, ClientError):
    logging.debug("ClientError raised while loading %s:\n%s", package.id, traceback.format_exc())
    continue

当运行此代码并且excClientError 类型时,format_exc() 只会打印出NoneType: None,因为当前没有处理异常(代码不在except 块内)。幸运的是,traceback 上的 format_exception 方法似乎与当前正在处理的异常无关,但为了调用它,我需要从我的异常变量中提取类型、值和 tb。我该怎么做?

【问题讨论】:

  • exc 是异常类的实例,还是只是一个类?如果是后者,那么isinstance 将不起作用。
  • exc 是异常类的一个实例。

标签: python exception exception-handling traceback


【解决方案1】:

exc 是如何产生的?如果它是从某个没有相应堆栈的函数返回的,那么无论如何都不可能产生正确的帧。最重要的是,没有going deep into ctypes 就无法生成Traceback 对象,因此这可能不是我们想要的。

如果您所追求的实际上是记录异常的堆栈,则使用inspect.currentframetraceback.format_stack 可能会产生您可能追求的东西。但是,如前所述,您需要让帧尽可能靠近发生错误的位置。考虑这个例子:

import traceback
import inspect
import logging


class Client:
    pass


class ClientError(Exception):
    pass


def get_client(name):
    if name is None:
        return ClientError('client must have a name')
    return Client()


def connect(target, name=None):
    exc = get_client(name)
    if isinstance(exc, ClientError):
        frames = inspect.currentframe()
        logging.debug("ClientError raised while loading %s:\n%s",
            target, ''.join(traceback.format_stack(frames)))


def main():
    connect('somewhere')


if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG)
    main()

执行此操作将产生以下输出:

DEBUG:root:ClientError raised while loading somewhere:
  File "foo.py", line 34, in <module>
    main()
  File "foo.py", line 30, in main
    connect('somewhere')
  File "foo.py", line 26, in connect
    target, ''.join(traceback.format_stack(frames)))

请注意,堆栈恰好在调用完成的地方结束,因为current_frame 的返回值限制为frames。这就是为什么堆栈应该在它产生的地方生成和格式化,然后退一步。考虑这些更新的函数:

def get_client(name):
    if name is None:
        return (
            ClientError('client must have a name'),
            traceback.format_stack(inspect.currentframe().f_back),
        )
    return Client(), None


def connect(target, name=None):
    exc, frames = get_client(name)
    if isinstance(exc, ClientError):
        stack = ''.join(frames)
        logging.debug("ClientError raised while loading %s:\n%s",
            target, stack)

执行

$ python foo.py 
DEBUG:root:ClientError raised while loading somewhere:
  File "foo.py", line 37, in <module>
    main()
  File "foo.py", line 33, in main
    connect('somewhere')
  File "foo.py", line 25, in connect
    exc, frames = get_client(name)

注意跟踪是如何在产生异常的函数处结束的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-29
    • 1970-01-01
    • 1970-01-01
    • 2017-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多