如何在Python中打印异常?

1400

except:块中如何打印错误/异常信息?

try:
    ...
except:
    print(exception)

11个回答

1903

对于Python 2.6及之后的版本和Python 3.x:

except Exception as e: print(e)

对于 Python 2.5 及更早版本,请使用:

except Exception,e: print str(e)

111
str(KeyError('bad')) 翻译为 'bad'。该代码未标明异常类型。 - Dave
45
在KeyError发生时使用print(e)只会显示键名,而不是完整的错误信息,这样并没有多大帮助。我建议对其进行改进。 - Veggiet
93
如果要打印异常信息,最好使用print(repr(e));基类Exception.__str__的实现仅返回异常信息而不包括类型。或者使用traceback模块,它具有用于打印当前异常的方法,可以格式化输出或以完整的回溯信息形式打印。 - Martijn Pieters
8
我在哪里声称打印 repr(e) 将会给出堆栈跟踪?我在谈论 str(e)repr(e) 之间的区别,后者包含了更多信息,你也会在回溯(traceback)的最后一行或几行看到这些信息。我在我的评论中明确提到了 traceback 模块。 - Martijn Pieters
3
@MartijnPieters虽然你没有这样做,但你确实建议使用print(repr(e)),而对于回溯(traceback)你只给出了一些通用语句,说明它有多种方法来打印异常。这听起来像是你更倾向于使用repr()方法,由于你的评论得到了很多赞,我认为值得写一个明显的回复,谈谈存在哪些更好的方法。 - Hi-Angel
显示剩余3条评论

783

traceback模块提供了用于格式化和打印异常及其回溯的方法,例如,这将打印类似于默认处理程序的异常:

import traceback

try:
    1/0
except Exception:
    traceback.print_exc()

输出:

Traceback (most recent call last):
  File "C:\scripts\divide_by_zero.py", line 4, in <module>
    1/0
ZeroDivisionError: division by zero

9
有没有一种叫做get_error_message的调用可以打印出来,因为我正在使用自己的打印程序添加一些其他内容。 - MikeSchem
62
错误信息 = traceback.format_exc() - heyzling
3
这段代码没有使用捕获的异常对象。你能否扩展代码以使用'ex'?- 就像except Exception as ex:... - aaronsteers
7
@aaronsteers,它确实使用了捕获的异常;在异常处理程序中,可以使用sys.exc_info()函数获取当前异常,并且traceback.print_exc()函数从那里获取异常。只有在不处理异常或想要基于不同的异常显示信息时,才需要显式传递异常。 - Martijn Pieters
6
是的,有时我想保留异常并在不再处于“except”块时打印它。 - aaronsteers
显示剩余3条评论

201

Python 2.6或更高版本中,这样会更简洁:

except Exception as e: print(e)

在旧版本中,它仍然相当易读:

except Exception, e: print e

129

Python 3: logging

除了使用基本的print()函数,更灵活的logging模块可以用于记录异常。该logging模块提供了额外的功能,例如:将日志信息...

  • 写入特定的日志文件中,或者
  • 带有时间戳和有关记录发生位置的其他信息。

欲了解更多信息,请查阅官方文档


用法

可以使用模块级别函数logging.exception()记录异常:

import logging

try:
    1/0
except BaseException:
    logging.exception("An exception was thrown!")

输出

ERROR:root:An exception was thrown!
Traceback (most recent call last):
File ".../Desktop/test.py", line 4, in <module>
    1/0
ZeroDivisionError: division by zero 

注意事项

  • 函数logging.exception()应该仅在异常处理程序中调用。

  • logging模块不应在日志处理程序内部使用,以避免RecursionError(感谢@PrakharPandey)。


备选日志级别

还可以使用关键字参数exc_info=True来记录另一个日志级别的异常,但仍显示异常详细信息。例如:

logging.critical("An exception was thrown!", exc_info=True)
logging.error   ("An exception was thrown!", exc_info=True)
logging.warning ("An exception was thrown!", exc_info=True)
logging.info    ("An exception was thrown!", exc_info=True)
logging.debug   ("An exception was thrown!", exc_info=True)

# or the general form
logging.log(level, "An exception was thrown!", exc_info=True)

仅包含名称和描述

当然,如果您不想要完整的回溯信息而只需要一些特定的信息(例如异常名称和描述),您仍然可以使用logging模块,例如:

try:
    1/0
except BaseException as exception:
    logging.warning(f"Exception Name: {type(exception).__name__}")
    logging.warning(f"Exception Desc: {exception}")

输出

WARNING:root:Exception Name: ZeroDivisionError
WARNING:root:Exception Desc: division by zero

6
不应在日志处理程序内使用,以避免出现递归错误。 - Prakhar Pandey
在这个例子中,异常被记录并且被“处理”了。如果没有得到足够的处理,可能希望重新引发此异常。 - sqqqrly
这个 "logging.exception()" 真是太棒了!它一直对我非常有效。相反地,当我记录 "Exception" 或其他答案时,有时候它工作得很好,有时候会打印出另一个 "error",有时候它不会告诉我错误的文件名和行号,有时候它会记录错误的文件和行号。 - Convexity

76

(我本来想在@jldupont的回答下留言,但我的声望不够。)

我在其他地方也看过像@jldupont的回答。顺便说一句,我认为需要注意的是这个:

except Exception as e:
    print(e)

默认情况下,会将错误输出打印到sys.stdout。一般来说,更合适的错误处理方法应该是:

except Exception as e:
    print(e, file=sys.stderr)

(请注意,您必须import sys才能使它工作)。这种方式将错误打印到STDERR而不是STDOUT,这允许正确输出解析/重定向/等。我知道问题严格是关于“打印错误”的,但似乎指出最佳实践比忽略此细节更为重要,否则对于任何最终没有学会更好的人来说,可能会导致非标准代码。

我没有像Cat Plus Plus的答案中那样使用traceback模块,也许那是最好的方法,但我想把这个方法提出来。


4
我建议进一步添加flush=True。我发现在使用systemd(而不是使用适当的日志框架)时,将输出缓存到journal时,缓冲区的行为与我的预期不同。 - Cameron Kerr
@CameronKerr 不是说 'stderr' 没有缓冲吗? - avighnac

70

如果您想传递错误字符串,这里有一个例子来自错误和异常(Python 2.6):

>>> try:
...    raise Exception('spam', 'eggs')
... except Exception as inst:
...    print type(inst)     # the exception instance
...    print inst.args      # arguments stored in .args
...    print inst           # __str__ allows args to printed directly
...    x, y = inst          # __getitem__ allows args to be unpacked directly
...    print 'x =', x
...    print 'y =', y
...
<type 'exceptions.Exception'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs

68

在捕获异常时,可以控制需要显示/记录的回溯信息。

代码:

with open("not_existing_file.txt", 'r') as text:
    pass

将会产生以下回溯信息:

Traceback (most recent call last):
  File "exception_checks.py", line 19, in <module>
    with open("not_existing_file.txt", 'r') as text:
FileNotFoundError: [Errno 2] No such file or directory: 'not_existing_file.txt'

打印/记录完整的回溯信息

正如其他人已经提到的,你可以使用traceback模块来捕获整个回溯信息:

import traceback
try:
    with open("not_existing_file.txt", 'r') as text:
        pass
except Exception as exception:
    traceback.print_exc()

这将会生成以下输出:

Traceback (most recent call last):
  File "exception_checks.py", line 19, in <module>
    with open("not_existing_file.txt", 'r') as text:
FileNotFoundError: [Errno 2] No such file or directory: 'not_existing_file.txt'

使用日志记录也可以实现相同的效果:

try:
    with open("not_existing_file.txt", 'r') as text:
        pass
except Exception as exception:
    logger.error(exception, exc_info=True)

输出:

__main__: 2020-05-27 12:10:47-ERROR- [Errno 2] No such file or directory: 'not_existing_file.txt'
Traceback (most recent call last):
  File "exception_checks.py", line 27, in <module>
    with open("not_existing_file.txt", 'r') as text:
FileNotFoundError: [Errno 2] No such file or directory: 'not_existing_file.txt'

仅打印/记录错误名称/消息

如果您只对最重要的信息(例如异常名称和异常消息)感兴趣,而不是整个回溯信息,请使用以下代码:

try:
    with open("not_existing_file.txt", 'r') as text:
        pass
except Exception as exception:
    print("Exception: {}".format(type(exception).__name__))
    print("Exception message: {}".format(exception))

输出:

Exception: FileNotFoundError
Exception message: [Errno 2] No such file or directory: 'not_existing_file.txt'

8
希望我能给这个回答点赞很多次,因为它比被采纳的那个回答更有帮助。 - LarsH
在你回答的最后一部分(“仅打印/记录错误名称\消息”)中,我如何仅使用一次“print”打印“异常”和“异常消息”?每当我尝试这样做时,它都变得很奇怪。 - pigeonburger
1
print(f"异常:{type(exception).name}\n异常信息:{exception}")。在开头的f表示这是一个f-string,它允许您将表达式放在花括号中,而不是使用.format()。但是,f-strings仅适用于运行Python 3.6+的系统。 - theProCoder

66

在这里扩展“except Exception as e:”解决方案,以下是一个好的一行解决方案,其中包括一些附加信息,如错误类型和错误发生的位置。


try:
    1/0
except Exception as e:
    print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")

输出:

ZeroDivisionError at line 48 of /Users/.../script.py: division by zero

2
最有用的答案。 - Trishant Pahwa
1
对于我来说,在Python 3.7 Anaconda中,pint(e)只返回Message:,没有其他内容。 - Farid Alijani
不得不滚动太远才能得到真正的答案。 - izzulmakin

36

试一下这个

try:
    print("Hare Krishna!")
except Exception as er:
    print(er)

12
通常情况下,没有解释的代码块不能算是一个很好的回答。如果您能告诉我们为什么应该尝试这个代码以及它为什么可能有助于问题的提出者,那么这将对社区更有帮助。谢谢! - Simas Joneliunas

4
我建议使用try-except语句。而且,不要使用print语句,使用日志记录异常会向记录器输出一个具有ERROR级别的消息,我发现这比打印输出更有效。该方法应仅在异常处理程序中调用,正如下面所示:
import logging

try:
    *code goes here*
except BaseException:
    logging.exception("*Error goes here*")

如果您想了解有关日志记录和调试的更多信息,请参阅此Python页面上的好文档。


在REPL中很难判断,我认为这会打印异常但不会停止程序,我的理解是:我仍然可以优雅地退出。 - Melendowski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接