Python中异常信息获取的最佳实践是什么?

在 php 里面,所有异常都可以用 getMessage 获取,但是 py 里面获取异常的方式信息感觉五花八门,难道就没有统一的方式吗? 我知道的方式有:

  1. str(err),大部分情况下可以,但是有时获取到的是空的
  2. err.message, 有些异常没有该属性,可能导致新的异常
  3. err.args[0], 有些异常的第一个属性为字符串,一个个属性为异常码,另一些却相反(没错,说的就是你,socket.errer!)

捕获一个异常后要去查文档才知道如何正确输出,心好累…

题外话:今天捕获到一个异常,message 属性存的居然不是字符串而是一个列表,一万个 mmp !


Python中异常信息获取的最佳实践是什么?

9 回复

import traceback
traceback.format_exc()


在Python里抓异常信息,最直接的就是用 traceback 模块。try-except 块里用 traceback.format_exc() 能拿到完整堆栈的字符串,写日志或者报错信息都很方便。

import traceback
import logging

logging.basicConfig(level=logging.ERROR)

try:
    # 你的主要代码逻辑,比如:
    result = 1 / 0
except Exception as e:
    # 获取完整的异常堆栈信息
    error_msg = traceback.format_exc()
    print("发生异常:")
    print(error_msg)
    # 记录到日志
    logging.error(error_msg)
    # 也可以只获取异常对象和它的信息
    print(f"异常类型: {type(e).__name__}")
    print(f"异常信息: {e}")

如果你需要更结构化的信息,比如单独获取文件名、行号,可以用 traceback.extract_tb() 来解析 sys.exc_info() 返回的 traceback 对象。

import sys
import traceback

try:
    result = 1 / 0
except Exception:
    exc_type, exc_value, exc_traceback = sys.exc_info()
    # 提取堆栈帧信息
    tb_list = traceback.extract_tb(exc_traceback)
    for frame in tb_list:
        print(f"文件: {frame.filename}, 行号: {frame.lineno}, 函数: {frame.name}, 代码行: {frame.line}")

简单说就是:要字符串就用 format_exc(),要解析就用 extract_tb()

logging.warning(‘ something ’, exc_info=True)

traceback 推荐.
(默认 python2)
简单写:
python<br>import traceback<br><br>try:<br> raise TypeError("Oups!")<br>except Exception, err:<br> try:<br> raise TypeError("Again !?!")<br> except:<br> pass<br><br> traceback.print_exc()<br>

如果要拿到详细信息:
python<br>import traceback<br>import sys<br><br>try:<br> raise TypeError("Oups!")<br>except Exception, err:<br> try:<br> exc_info = sys.exc_info()<br><br> # do you usefull stuff here<br> # (potentially raising an exception)<br> try:<br> raise TypeError("Again !?!")<br> except:<br> pass<br> # end of useful stuff<br><br><br> finally:<br> # Display the *original* exception<br> traceback.print_exception(*exc_info)<br> del exc_info<br>````<br><br>输出结果类似如下:<br>python
Traceback (most recent call last):
File “t.py”, line 6, in <module>
raise TypeError(“Oups!”)
TypeError: Oups!
<br><br><br>python3 的话, 输出信息会少一些。<br>python
import traceback

try:
raise TypeError(“Oups!”)
except Exception as err:
try:
raise TypeError(“Again !?!”)
except:
pass

traceback.print_tb(err.traceback)
<br><br>输出大致如下:<br>
File “e3.py”, line 4, in <module>
raise TypeError(“Oups!”)
```

关键是还是去看官方文档 traceback 模块:
python2.7: https://docs.python.org/2/library/traceback.html
python3.6: https://docs.python.org/3/library/traceback.html

我的经验来自: [stackoverflow 链接]( https://stackoverflow.com/questions/3702675/how-to-print-the-full-traceback-without-halting-the-program)

可以试一下 vars(error),可以看到这个对象所有的属性和值。如果提示错误的话,就用 dir(error),可以看到这个对象的所有属性。

不过最好还是去看源码里看,这个 error 是怎么抛出,怎么构造的~

V2EX 支持嵌入 Gist 资源,若要展示源码,最好写在那上面,再贴链接过来即可。

BaseException.args 是 python2.5 新增的属性,可以知道用户传递的是什么内容。

print(Exception(1, 2, 3).args)
# (1, 2, 3)

print(Exception(‘xyz’).args)
# (‘xyz’,)

print(Exception().args)
# ()

初步了解了下 PHP 的 getMessage() 类似 python 中限定了参数为字符串的异常。

python 的异常里的内容可以是任何东西,写入的是啥,取出来的就是啥了。
异常 catcher 并不能做什么,只能规范异常 raiser 的行为。

如果 catcher 和 raiser 都是可控制的代码,可以自定义的异常,用这种方式规范代码。示例:

class SomethingError(Exception):
def init(self, code, message, blablabla):
self.code = code
self.message = message
self.blabla = blabla

然而即使如此,raiser 仍然可以不按“规范” raise Somthing(‘string’, 666, []) 。
python 语言本身没有限制用户的行为,靠用户自觉。

一般委托给 logging.exception 或者 logging.[error|warn|info|debug](…, exc_info=True)

回到顶部