如何在Python中退出且不显示回溯信息?

307
我想知道如何在退出Python时不在输出中生成回溯转储。我仍然希望能够返回错误代码,但我不想显示回溯日志。我想使用exit(number)退出,但如果发生异常(而不是退出),则需要跟踪。

10
sys.exit()会在不打印回溯信息的情况下停止执行,而引发异常则不会。因此,如果您的问题描述了默认行为,那么无需更改任何内容。 - Luper Rouch
2
@Luper 很容易检查 sys.exit() 是否抛出 SystemExit 异常! - Val
5
我说它不会打印出回溯信息,而不是它不会引发异常。 - Luper Rouch
我认为这真正回答了你所问的问题:https://dev59.com/-3VC5IYBdhLWcg3w1Etq - Stefan
3
这个问题是特别针对 Jython 2.4 或者类似版本的吗?因为对于现代版本的 Python(即使在2009年,这意味着CPython 2.6和3.1、Jython 2.5和IronPython 2.6),这个问题毫无意义,而且前面最佳答案是错误的。 - abarnert
显示剩余2条评论
10个回答

320
你可能遇到了异常,程序因此退出(带有traceback)。因此,首先要捕获异常,然后干净地退出(可以使用消息进行提示,例如给出的示例)。
在你的main函数中尝试以下代码:
import sys, traceback

def main():
    try:
        do main program stuff here
        ....
    except KeyboardInterrupt:
        print "Shutdown requested...exiting"
    except Exception:
        traceback.print_exc(file=sys.stdout)
    sys.exit(0)

if __name__ == "__main__":
    main()

13
如果在“主程序部分”调用sys.exit(),上面的代码会丢弃传递给sys.exit的值。注意,sys.exit引发SystemExit异常,变量“e”将包含退出代码。 - bstpierre
6
建议使用 stderr 进行打印,代码为 sys.stderr.write(msg)。 - vinilios
20
强烈建议删除从except Exception:sys.exit(0)的代码行,包括这两行。对于所有未处理的异常,默认行为已经是打印回溯信息并在代码结束后退出,因此手动执行相同操作是多余的。 - MestreLion
7
关于你的评论:在程序中应该使用sys.exit(),而exit()则用于交互式Shell。详见Python中exit()和sys.exit()的区别? - ire_and_curses
2
@Pierre:但是按照这种写法,它不会做到这一点——它将打印异常,然后退出而没有错误代码。这几乎是你想要的完全相反。 - abarnert
显示剩余7条评论

87

也许你试图捕获所有异常,但这里却捕获了由sys.exit()引发的SystemExit异常?

import sys

try:
    sys.exit(1) # Or something that calls sys.exit()
except SystemExit as e:
    sys.exit(e)
except:
    # Cleanup and reraise. This will print a backtrace.
    # (Insert your cleanup code here.)
    raise

通常情况下,使用except:而不指定异常名称是个坏主意。你会捕获到各种不想捕获的东西,比如SystemExit,它也可能掩盖你自己的编程错误。我上面的例子很愚蠢,除非你正在进行清理方面的工作。你可以将其替换为:

import sys
sys.exit(1) # Or something that calls sys.exit().

如果您需要在不引发SystemExit的情况下退出:

import os
os._exit(1)

我在运行 unittest 并调用 fork() 的代码中执行此操作。当 fork 的进程引发 SystemExit 时,unittest 就会获取到它。这绝对是一个边角情况!


6
这段代码很傻:为什么要捕获SystemExit,只是为了调用sys.exit(e)?删除这两行代码会产生同样的效果。此外,清理工作应该属于finally:部分,而不是except Exception: ... raise. - MestreLion
@MestreLion:你可以自由地点踩,但是如果你读了我在你的评论上面的评论,那只对2.5+有效。如果你读了我的所有帖子,我明确表示代码很愚蠢,并建议你在评论中所说的正是我的建议。 - bstpierre
2
抱歉,你是对的...我忘记了Python 2.5中有一个重大的异常重构。我试图取消投票,但SO只允许我在回答被编辑后才能这样做。所以,既然我们已经进入2012年,Python 2.4已经成为历史,为什么不编辑它并展示正确(当前)的代码,将pre-2.5方法作为脚注呢?这将极大地改善答案,我将能够取消投票,并乐意这样做。对每个人来说都是双赢 :) - MestreLion
@MestreLion:我按照您的建议开始编辑,但这个答案只有在问题和2.4环境的背景下才有意义。这个踩票并没有让我不爽。 - bstpierre

48
import sys
sys.exit(1)

19
以下代码不会引发异常,并且将退出而无需跟踪:
import os
os._exit(1)

查看此问题及相关答案以获取更多细节。惊讶于为什么所有其他答案都过于复杂。

这种方法也不能进行适当的清理,例如调用清理处理程序、刷新stdio缓冲区等(感谢pabouk指出这一点)。


1
不适用于正常退出。此解决方案绕过了所有Python清理代码! - pabouk - Ukraine stay strong

10

类似于 import sys; sys.exit(0) 的东西吗?


@mestreLion那我为什么会在我的控制台上看到以下内容:Dets 06 18:53:17 Traceback (most recent call last): File "debug_new.py", line 4, in <module> import sys; sys.exit(0) SystemExit: 0 at org.python.core.PyException.fillInStackTrace(PyException.java:70) - Val
3
@Val: 因为你没有使用标准的 Python 控制台。Jython 并非 Python,看起来它(或者至少它的控制台)处理异常的方式不同。 - MestreLion
@Val 请查看为什么sys.exit()会导致回溯? - Stevoisiak

5

最好的实践是避免使用sys.exit(),而是使用raise/handle异常来让程序能够干净地结束。如果你想关闭追踪回溯(traceback),只需使用:

sys.trackbacklimit=0

您可以在脚本顶部设置此选项以消除所有回溯输出,但我更喜欢谨慎使用它,例如在“已知错误”方面,我希望输出干净,例如在文件foo.py中:
import sys
from subprocess import *

try:
  check_call([ 'uptime', '--help' ])
except CalledProcessError:
  sys.tracebacklimit=0
  print "Process failed"
  raise

print "This message should never follow an error."

如果捕获到CalledProcessError,则输出结果将如下所示:

[me@test01 dev]$ ./foo.py
usage: uptime [-V]
    -V    display version
Process failed
subprocess.CalledProcessError: Command '['uptime', '--help']' returned non-zero exit status 1

如果发生其他错误,我们仍然可以获得完整的回溯输出。

1
关于在Python 3中使用sys.trackbacklimit,请参见此答案 - Asclepius
1
请将错误信息发送到stderr,而不是stdout。使用以下代码:print("Process failed", file=sys.stderr) - pabouk - Ukraine stay strong

3

使用内置的python函数quit()即可完成,无需导入任何库。我正在使用Python 3.4版本。


请勿在您的代码中使用 quit()exit()。这些函数仅适用于交互式 Python。请参阅 Python 退出命令 - 为什么有这么多,每个应该在何时使用? 您可以使用 sys.exit()raise SystemExit 替代。 - pabouk - Ukraine stay strong

2
我会这样做:

我会这样做:

import sys

def do_my_stuff():
    pass

if __name__ == "__main__":
    try:
        do_my_stuff()
    except SystemExit, e:
        print(e)

-1

关于什么呢?

import sys
....
....
....
sys.exit("I am getting the heck out of here!")

没有追踪信息,但更加明确。


-9
# Pygame Example  

import pygame, sys  
from pygame.locals import *

pygame.init()  
DISPLAYSURF = pygame.display.set_mode((400, 300))  
pygame.display.set_caption('IBM Emulator')

BLACK = (0, 0, 0)  
GREEN = (0, 255, 0)

fontObj = pygame.font.Font('freesansbold.ttf', 32)  
textSurfaceObj = fontObj.render('IBM PC Emulator', True, GREEN,BLACK)  
textRectObj = textSurfaceObj.get_rect()  
textRectObj = (10, 10)

try:  
    while True: # main loop  
        DISPLAYSURF.fill(BLACK)  
        DISPLAYSURF.blit(textSurfaceObj, textRectObj)  
        for event in pygame.event.get():  
            if event.type == QUIT:  
                pygame.quit()  
                sys.exit()  
        pygame.display.update()  
except SystemExit:  
    pass

8
如果您对代码进行注释,将提高答案的质量。 - user3413108

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