可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a code similar to this:
try:
if x:
statement1
statement2
statement3
elif y:
statement4
statement5
statement6
else:
raise
except:
statement7
Here, I am sure that the exception occurs in If x:
block, but I would like to know in which statement of If x:
block the exception occurs. Is there a way to get the line number where the exception occurs?
Regards,
回答1:
what about this:
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
this is the straightforward workaround but I suggest to use a debugger
or even better, use the sys module :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
回答2:
I believe the several answers here recommending you manage your try/except
blocks more tightly are the answer you're looking for. That's a style thing, not a library thing.
However, at times we find ourselves in a situation where it's not a style thing, and you really do need the line number to do some other programattic action. If that's what you're asking, you should consider the traceback
module. You can extract all the information you need about the most recent exception. The tb_lineno
function will return the line number causing the exception.
>>> 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
Newer versions of the traceback plumbing fix the issue prior to 2.3, allowing the code below to work as it was intended: (this is the "right way")
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)
回答3:
You should run your program in a debugger, such as pdb
. This will allow you to run your code normally, and then examine the environment when something unexpected like this occurs.
Given a script named 'main.py', run it like this:
python -m pdb main.py
Then, when your program starts, it will start in the debugger. Type c
to continue until the next breakpoint (or crash). Then, you can examine the environment by doing things like print spam.eggs
. You can also set breakpoints by doing pdb.set_trace()
(I commonly do import pdb; pdb.set_trace()
).
Additionally, what do you mean that it is "okay" for 'statement 3' to raise the exception? Are you expecting the exception? If so, it might be better to write a try/except block around this statement, so that the program can continue.
回答4:
I've done the following before:
try:
doing = "statement1"
statement1
doing = "statement2"
statement2
doing = "statement3"
statement3
doing = "statement4"
statement4
except:
print "exception occurred doing ", doing
The advantage over printing checkpoints is there's no log output unless
there actually is an exception.
回答5:
Building on JJ above..
The advantage of using system errors over statements is they record more specific information which will aid debugging later (believe me I get a lot)
eg. I record them to a text file, so after my programs have automatically run overnight on the server, I can retrieve any issues, and have enough information to quicken the repair!
More Info... Traceback & Sys
import traceback
import sys
try:
print 1/0
except Exception as e:
print '1', e.__doc__
print '2', sys.exc_info()
print '3', sys.exc_info()[0]
print '4', sys.exc_info()[1]
print '5', sys.exc_info()[2], 'Sorry I mean line...',traceback.tb_lineno(sys.exc_info()[2])
ex_type, ex, tb = sys.exc_info()
print '6', traceback.print_tb(tb)
Yields
> 1 Second argument to a division or modulo operation was zero.
> 2 (<type 'exceptions.ZeroDivisionError'>, ZeroDivisionError('integer division
> or modulo by zero',), <traceback object at 0x022DCF30>)
> 3 <type 'exceptions.ZeroDivisionError'>
> 4 integer division or modulo by zero
> 5 <traceback object at 0x022DCF30> Sorry I mean line... 5
> 6 File "Z:\Programming\Python 2.7\Error.py", line 5, in <module>
> print 1/0
None
>>>
回答6:
You should wrap the statements you care about more tightly. Extracting the line number from the traceback is going to be involved and fragile.
回答7:
If you restructure the code like so, you should get a line number when the exception is raised again:
except:
statement7
raise
回答8:
Using a general except statement is usually a bad programming practice, so you should specify in your except statement what exception you want to catch. ( like except ValueError: )
Moreover, you should surround with a try except structure the bits of code that are supposed to be raising an exception.
回答9:
Edit your source code, so that you remove one line at a time, until the error disappears, and that should point you closer to the problem.
回答10:
we can get the line number by splitting the string state of the traceback.format_exc()
.
please try running the following code..
import traceback
try:
a = "str"
b = 10
c = a + b
except Exception as e:
err_lineno = str(traceback.format_exc()).split(",")[1]
print(err_lineno)
this will produce the following output
line 7