定位Python代码中异常发生的行号

10 投票
10 回答
23908 浏览
提问于 2025-04-16 22:59

我有一段代码,类似于这个:

try:
  if x:
      statement1
      statement2
      statement3
  elif y:
      statement4
      statement5
      statement6
  else:
      raise

except:
      statement7

在这里,我确定异常发生在 If x: 这个块里,但我想知道在 If x: 这个块中的哪一行出现了异常。有没有办法找到异常发生的行号呢?

谢谢,

10 个回答

4

你应该在调试器中运行你的程序,比如说 pdb。这样的话,当你的代码出现意外情况时,你可以正常运行代码,然后检查一下当时的环境。

假设你有一个叫做 'main.py' 的脚本,你可以这样运行它:

python -m pdb main.py

然后,当你的程序启动时,它会在调试器中开始运行。你可以输入 c 来继续执行,直到下一个断点(或者崩溃)。接着,你可以通过输入像 print spam.eggs 这样的命令来检查环境。你还可以通过输入 pdb.set_trace() 来设置断点(我通常会写 import pdb; pdb.set_trace())。

另外,你说 'statement 3' 抛出异常是“可以的”,这是什么意思呢?你是期待这个异常吗?如果是这样的话,可能更好的是在这个语句周围写一个 try/except 块,这样程序就可以继续运行了。

13

我觉得这里有几个回答建议你更好地管理你的 try/except 代码块,这正是你想要的答案。这是一个风格问题,而不是库的问题。

不过,有时候我们会遇到一种情况,这不仅仅是风格问题,你确实需要行号来进行其他编程操作。如果你在问这个,建议你看看 traceback 模块。这个模块可以提取你需要的关于最近一次异常的所有信息。tb_lineno 函数会返回导致异常的行号。

>>> import traceback
>>> dir(traceback)
['__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_format_final_exc_line', '_print', '_some_str', 'extract_stack', 'extract_tb', 'format_exc', 'format_exception', 'format_exception_only', 'format_list', 'format_stack', 'format_tb', 'linecache', 'print_exc', 'print_exception', 'print_last', 'print_list', 'print_stack', 'print_tb', 'sys', 'tb_lineno', 'types']
>>> help(traceback.tb_lineno)
Help on function tb_lineno in module traceback:

tb_lineno(tb)
Calculate correct line number of traceback given in tb.
Obsolete in 2.3

更新版本的 traceback 处理修复了 2.3 之前的问题,让下面的代码可以按预期工作: (这就是“正确的方法”)

import traceback
import sys

try:
    raise Exception("foo")
except:
    for frame in traceback.extract_tb(sys.exc_info()[2]):
        fname,lineno,fn,text = frame
        print "Error in %s on line %d" % (fname, lineno)
21

那这个怎么样:

try:
  if x:
      print 'before statement 1'
      statement1
      print 'before statement 2' #ecc. ecc.
      statement2
      statement3
  elif y:
      statement4
      statement5
      statement6
  else:
      raise

except:
      statement7

这是一个简单直接的解决办法,但我建议你使用调试工具。

更好的是,使用sys模块 :D

try:
      if x:
          print 'before statement 1'
          statement1
          print 'before statement 2' #ecc. ecc.
          statement2
          statement3
      elif y:
          statement4
          statement5
          statement6
      else:
          raise
except:
    print sys.exc_traceback.tb_lineno 
    #this is the line number, but there are also other infos

撰写回答