Python:使用sys.exit或SystemExit的差异和建议
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python:使用sys.exit或SystemExit的差异和建议相关的知识,希望对你有一定的参考价值。
在线阅读一些程序员使用sys.exit
,其他人使用SystemExit
。
对不起,基本问题是:
- 有什么不同?
- 我什么时候需要在函数内使用SystemExit或sys.exit?
例
ref = osgeo.ogr.Open(reference)
if ref is None:
raise SystemExit('Unable to open %s' % reference)
要么
ref = osgeo.ogr.Open(reference)
if ref is None:
print('Unable to open %s' % reference)
sys.exit(-1)
没有实际区别,但是你的示例代码还有另一个区别 - print
转到标准输出,但异常文本转到标准错误(这可能是你想要的)。
sys.exit(s)
只是raise SystemExit(s)
的简写,正如前者的文档中描述的那样;试试help(sys.exit)
。因此,您可以这样做,而不是您的任何一个示例程序
sys.exit('Unable to open %s' % reference)
除了提升SystemExit
外,还有3个退出功能。
底层的是os._exit
,它需要1个int参数,并且在没有清理的情况下立即退出。你不太可能想触摸这个,但它就在那里。
sys.exit
在sysmodule.c中定义,只运行PyErr_SetObject(PyExc_SystemExit, exit_code);
,实际上与直接提升SystemExit
相同。在细节上,提高SystemExit
可能更快,因为sys.exit
需要LOAD_ATTR
和CALL_FUNCTION
vs RAISE_VARARGS
opcalls。此外,raise SystemExit
产生稍小的字节码(少4字节),(如果使用from sys import exit
则额外增加1个字节,因为预期sys.exit
将返回None,因此包含额外的POP_TOP
)。
最后一个退出函数在site.py
中定义,并在REPL中别名为exit
或quit
。它实际上是Quitter
类的一个实例(所以它可以有一个自定义的__repr__
,因此可能是最慢的运行。此外,它在提升sys.stdin
之前关闭SystemExit
,因此建议仅在REPL中使用。
至于如何处理SystemExit
,它最终会导致VM调用os._exit,但在此之前,它会进行一些清理。它还运行atexit._run_exitfuncs()
,它运行通过atexit
模块注册的任何回调。直接调用os._exit
绕过atexit
步骤。
我个人的偏好是,至少SystemExit
被提升(或者甚至更好 - 一个更有意义且记录良好的自定义异常),然后尽可能接近“主要”功能,这可能有最后一次机会认可它是否有效退出。从设计的角度来看,拥有sys.exit
的图书馆/深度嵌入式功能简直令人讨厌。 (一般来说,退出应尽可能“高涨”)
SystemExit
是一个例外,这基本上意味着你的程序有一个行为,你想要停止它并引发错误。 sys.exit
是您可以调用退出程序的函数,可能会给系统返回代码。
编辑:它们确实是同一个东西,所以唯一的区别在于你的程序背后的逻辑。一个例外是某种“不需要的”行为,无论从程序员的角度来看,对函数的调用是更多的“标准”动作。
根据文件sys.exit(s)
有效地做raise SystemExit(s)
,所以它几乎是相同的事情。
尽管许多答案都回答了这种差异,但https://mail.python.org/pipermail/python-list/2016-April/707470.html提出了一个有趣的观点:
TL; DR:最好只引发“正常”异常,并仅在脚本的顶层使用SystemExit
或sys.exit
。
我在python 2.7和Linux上,如果我可以用raise SystemExit替换sys.exit(1),我有一个简单的代码需要建议。
==实际代码==
def main(): try: create_logdir() create_dataset() unittest.main() except Exception as e: logging.exception(e) sys.exit(EXIT_STATUS_ERROR) if __name__ == '__main__': main()
==更改代码==
def main(): try: create_logdir() create_dataset() unittest.main() except Exception as e: logging.exception(e) raise SystemExit if __name__ == '__main__': main()
我个人反对这两个人。我喜欢的模式是这样的:
def main(argv): try: ... except Exception as e: logging.exception(e) return 1 if __name__ == '__main__': sys.exit(main(sys.argv))
请注意,main()恢复为具有正常返回的正常函数。
此外,我们大多数人会避免“除了异常”,只是让顶级除泡沫外:这样你就可以得到一个堆栈回溯来进行调试。我同意它可以防止记录异常并使得更加丑陋的控制台输出,但我认为这是一个胜利。如果您确实要记录异常,则始终如下:
尝试:...除了异常e:logging.exception(e)raise
将异常记录到日志中仍然让它正常冒出来。
“异常除外”模式的问题在于它捕获并隐藏了每个异常,而不仅仅是您理解的一小组特定异常。
最后,提出一个裸露的Exception类是不受欢迎的。在python 3中我认为它实际上是被禁止的,所以它无论如何都是不可移植的。但即使在Python中,最好提供一个Exception实例,而不是类:
提升SystemExit(1)
- try块中的所有函数都有使用raise冒出的异常 create_logdir()的示例是函数定义
def create_logdir():
尝试:os.makedirs(LOG_DIR),除了OSError为e:sys.stderr.write(“无法创建日志目录...退出!!!”)提示打印“日志文件:”+ corrupt_log返回True
def main():try:create_logdir()除了Exception为e:logging.exception(e)引发SystemExit
(a)如果create_logdir()失败,我们将得到以下错误,这是好还是我需要改进此代码。
无法创建日志目录...退出!!!错误:root:[Errno 17]文件存在:'/ var / log / dummy'
回溯(最近调用最后一次):文件“corrupt_test.py”,第245行,在主create_logdir()文件“corrupt_test.py”,第53行,在create_logdir os.makedirs(LOG_DIR)文件“/ usr / local / lib / python2.7 / os.py“,第157行,在makedirs中OSError:[Errno 17]文件存在:'/ var / log / dummy'
我更喜欢冒出泡沫的方法,如你所做的那样使用日志或警告信息进行预测,例如:
logging.exception(“create_logdir failed:makedirs(%r):%s”%(LOG_DIR,e))raise
(也不是说该日志消息记录了更多上下文:上下文在调试问题时非常有用。)
对于非常小的脚本,sys.stderr.write是可以的,但一般来说,任何通常有用的函数都可以迁移到库中以便重用;认为stderr并不总是消息的地方;而是根据需要读取带有error()或wanr()或exception()的日志记录模块。有更多的空间可以配置输出的方式,而无需将其连接到内部函数中。
- 我可以加注,而不是SystemExit或sys.exit(1)。这看起来对我不对 def main(): 尝试:create_logdir()除了异常,因为e logging.exception(e)raise
这就是我自己要做的。
想一想:异常是“处理”了,意味着已经处理了这种情况,因为它是预期的吗?如果没有,请让异常冒出来,以便用户知道程序不理解的内容已经发生。
最后,除了最外层的main()函数之外的任何东西,SystemExit或sys.exit()通常都是坏的。我甚至在那里抵抗它;主要功能,如果写得好,通常可以从其他地方有用地调用,这使它有效地成为库函数(它已被重用)。这种功能不应单方面中止该计划。太粗鲁了!相反,让异常冒出来:也许main()的调用者需要它并且可以处理它。通过中止而不是“提升”,即使你自己(即“主要”)不知道足够的上下文来处理异常,你也剥夺了调用者做某事的机会。
所以我是为了“抚养”自己。然后只是因为你想记录错误。如果你不想记录异常,你可以完全避免try / except并且代码更简单:让调用者担心未处理的异常!
以上是关于Python:使用sys.exit或SystemExit的差异和建议的主要内容,如果未能解决你的问题,请参考以下文章
python控制流 -- ifforwhilerange()sys.exit()
python中使用sys模块中sys.exit()好像不能退出?
Python3.x:os._exit(), sys.exit(), exit() 的区别