BDFL在2003年发表了一篇关于如何编写Python主函数的文章。他的例子是这样的:
import sys
import getopt
class Usage(Exception):
def __init__(self, msg):
self.msg = msg
def main(argv=None):
if argv is None:
argv = sys.argv
try:
try:
opts, args = getopt.getopt(argv[1:], "h", ["help"])
except getopt.error, msg:
raise Usage(msg)
# more code, unchanged
except Usage, err:
print >>sys.stderr, err.msg
print >>sys.stderr, "for help use --help"
return 2
if __name__ == "__main__":
sys.exit(main())
将可选参数argv
改为main()
的原因是,"我们将main()
更改为可选参数argv
,这允许我们从交互式Python提示符中调用它。"
他这样解释他的代码的最后一行:
现在
sys.exit()
调用很烦人:当main()
调用sys.exit()
时,交互式Python解释器将退出!补救的办法是放手main()
的返回值指定退出状态。的代码Very end变成if __name__ == "__main__": sys.exit(main())
和
main()
内部对sys.exit(n)
的调用都变成了return n
。
然而,当我在Spyder控制台中运行Guido的代码时,它杀死了解释器。我遗漏了什么?我的意图是只有import
模块具有这种类型的main()
,从不只是用execfile
或runfile
执行它们?这不是我倾向于做交互开发的方式,特别是考虑到它需要我记住在import foo
和reload(foo)
之间来回切换。
我知道我可以从getopt
中捕获SystemExit
,或者尝试使用一些黑魔法来检测Python是否正在交互运行,但我认为这两种方法都不是BDFL的意图。
您的选择是不使用execfile
或传递不同的__name__
值作为全局:
execfile('test.py', {'__name__': 'test'})
默认是将文件作为脚本运行,这意味着将__name__
设置为__main__
。
你引用的文章只适用于import
.
另一种处理方法是尝试检测您是否处于交互式上下文中,我在问题中简要地提到了这一点。我不相信这是可以移植的,但这里有它,以防它对某人有帮助:
if __name__ == "__main__":
if 'PYTHONSTARTUP' in os.environ:
try:
main() # Or whatever you want to do here
except SystemExit as se:
logging.exception("")
else:
sys.exit(main())