如何在使用 execfile 时防止运行 __main__ 守卫?

5 投票
2 回答
2017 浏览
提问于 2025-04-18 06:51

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()改成可以接受一个可选的argv参数,这样我们就可以在Python的交互式提示符下调用它。”

他对代码最后一行的解释是:

现在sys.exit()的调用有点麻烦:当main()调用sys.exit()时,你的交互式Python解释器会直接退出!解决办法是让main()的返回值来指定退出状态。因此,最后的代码变成了:

if __name__ == "__main__":
    sys.exit(main())

而在main()内部对sys.exit(n)的调用都变成了return n

不过,当我在Spyder控制台运行Guido的代码时,它会直接关闭解释器。我是不是漏掉了什么?是不是说我只能import那些有这种类型main()的模块,而不能直接用execfilerunfile来执行它们?这不是我平常做交互式开发的方式,尤其是这还要求我记得在import fooreload(foo)之间来回切换。

我知道我可以捕获SystemExit,或者试着用一些黑魔法来检测Python是否在交互模式下运行,但我想这都不是BDFL的本意。

2 个回答

0

还有一种处理方法,我在问题中稍微提到过,就是尝试检测你是否处于一个互动的环境中。我认为这并不能在所有情况下都适用,但如果对某些人有帮助的话,可以看看这个方法:

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())
11

你有两个选择:要么不使用 execfile,要么传入一个不同的 __name__ 值作为全局变量。

execfile('test.py', {'__name__': 'test'})

默认情况下,运行这个文件就像运行一个脚本,这样 __name__ 的值会被设置为 __main__

你提到的那篇文章只适用于 import

撰写回答