Gia*_*ear 44 python performance coding-style
在线阅读一些程序员使用sys.exit,其他人使用SystemExit.
对不起,基本问题是:
例
ref = osgeo.ogr.Open(reference)
if ref is None:
raise SystemExit('Unable to open %s' % reference)
Run Code Online (Sandbox Code Playgroud)
要么
ref = osgeo.ogr.Open(reference)
if ref is None:
print('Unable to open %s' % reference)
sys.exit(-1)
Run Code Online (Sandbox Code Playgroud)
Fre*_*Foo 28
sys.exit(s)只是简写raise SystemExit(s),正如前者的文档中描述的那样; 试试help(sys.exit).因此,您可以这样做,而不是您的任何一个示例程序
sys.exit('Unable to open %s' % reference)
Run Code Online (Sandbox Code Playgroud)
Ric*_*dle 25
没有实际的区别,但是你的示例代码还有另一个区别 - print转到标准输出,但异常文本转到标准错误(这可能是你想要的).
Per*_*ins 10
除了提升之外,还有3个退出功能SystemExit.
底层的是os._exit,需要1个int参数,并且在没有清理的情况下立即退出.你不太可能想触摸这个,但它就在那里.
sys.exit在sysmodule.c中定义并且只是运行PyErr_SetObject(PyExc_SystemExit, exit_code);,这实际上与直接引发相同SystemExit.在细节方面,提高SystemExit可能更快,因为sys.exit需要LOAD_ATTR和CALL_FUNCTIONvs RAISE_VARARGSopcalls.此外,raise SystemExit产生稍小的字节码(少4字节),(如果你使用from sys import exit,sys.exit则额外增加1个字节, 因为预期返回None,所以包括额外的POP_TOP).
最后一个退出函数在REPL中定义site.py,或别名exit或quit在REPL中.它实际上是Quitter类的一个实例(所以它可以有一个自定义__repr__,因此可能是最慢的运行.而且,它sys.stdin在提升之前关闭SystemExit,因此建议仅在REPL中使用.
至于如何SystemExit处理,最终会导致VM调用os._exit,但在此之前,它会进行一些清理.它还运行atexit._run_exitfuncs(),运行通过atexit模块注册的任何回调.os._exit直接呼叫绕过该atexit步骤.
我个人的偏好是至少SystemExit提出(或者甚至更好 - 一个更有意义且记录良好的自定义异常)然后尽可能接近"主要"功能,这可能有最后的机会认为它是有效退出与否.sys.exit从设计的角度来看,图书馆/深度嵌入的功能只是简单的讨厌.(一般来说,退出应尽可能"高涨")
虽然许多答案都回答了这种差异,但 Cameron Simpson 在https://mail.python.org/pipermail/python-list/2016-April/857869.html中提出了一个有趣的观点:
TL;DR:最好只引发“正常”异常,并仅在脚本的顶层使用SystemExitor 。sys.exit
我使用 python 2.7 和 Linux ,如果我可以用 raise SystemExit 替换 sys.exit(1) ,我有一个简单的代码需要建议。
==实际代码==
Run Code Online (Sandbox Code Playgroud)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()==更改代码==
Run Code Online (Sandbox Code Playgroud)def main(): try: create_logdir() create_dataset() unittest.main() except Exception as e: logging.exception(e) raise SystemExit if __name__ == '__main__': main()我个人反对这两种做法。我的首选模式是这样的:
Run Code Online (Sandbox Code Playgroud)def main(argv): try: ... except Exception as e: logging.exception(e) return 1 if __name__ == '__main__': sys.exit(main(sys.argv))请注意,main() 又恢复为具有正常返回值的正常函数。
另外,我们大多数人都会避免“ except Exception”,而只是让顶层 except 冒泡出来:这样你就可以获得用于调试的堆栈回溯。我同意它可以防止记录异常并导致控制台输出变得更丑陋,但我认为这是一个胜利。如果你确实想记录异常,总是这样:
尝试:... except Exception as e:logging.exception(e) raise
将异常记录到日志中并仍然让它正常冒泡。
“除了异常”模式的问题在于它捕获并 隐藏 每个异常,而不仅仅是您理解的一小部分特定异常。
最后,引发一个裸露的 Exception 类是不被允许的。在 python 3 中,我相信它实际上是被禁止的,所以无论如何它都是不可移植的。但即使在 Python 中,最好提供一个 Exception 实例,而不是类:
引发系统退出(1)
- try 块中的所有函数都使用 raise 引发异常
create_logdir() 的示例是函数定义
def create_logdir():
尝试: os.makedirs(LOG_DIR) except OSError as e: sys.stderr.write("无法创建日志目录...退出!!!") raise print "日志文件:" + Corrupt_log return True
def main(): 尝试: create_logdir() except Exception as e:logging.exception(e) raise SystemExit
(a) 如果 create_logdir() 失败,我们将收到以下错误,这可以吗还是我需要改进此代码。
无法创建日志目录...正在退出!错误:根:[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 失败: makedirs(%r): %s" % (LOG_DIR, e)) raise
(也不是说该日志消息记录了更多上下文:上下文在调试问题时非常有用。)
对于非常小的脚本 sys.stderr.write 是可以的,但一般来说,任何通常有用的函数都可能会迁移到库中以便重用;考虑到 stderr 并不总是存放消息的地方;相反,根据需要使用 error() 或 wanr() 或 exception() 读取日志记录模块。有更多的空间来配置输出的位置,而无需将其连接到内部函数中。
- 我可以直接 raise ,而不是 SystemExit 或 sys.exit(1) 吗?这对我来说看起来不对
def main():
尝试:create_logdir() except Exception as elogging.exception(e) raise
这就是我自己会做的事情。
想一想:异常是否已被“处理”,即情况是否因为预期而得到处理?如果没有,则让异常冒出,以便用户知道发生了程序无法理解的事情。
最后,除了最外面的 main() 函数之外,从任何内部调用 SystemExit 或 sys.exit() 通常都是不好的。即使在那里我也抗拒它;main 函数,如果写得好,通常可以从其他地方有效地调用,这使得它实际上成为一个库函数(它已被重用)。这样的函数不应该单方面中止程序。太粗鲁了!相反,让异常冒出来:也许main() 的调用者期望它并且可以处理它。通过中止而不是“引发”,您剥夺了调用者执行适当操作的机会,即使您自己(即“main”)不知道足够的上下文来处理异常。
所以我主张“提高”自己。然后只是因为您想记录错误。如果您不想记录异常,您可以完全避免 try/ except 并使用更简单的代码:让调用者担心未处理的异常!
| 归档时间: |
|
| 查看次数: |
42289 次 |
| 最近记录: |