2

在一个交互式运行的 python 会话中,我启动了我使用编写的模块/程序argparse(因为这些模块也被用作来自 shell 提示符的命令)。

如果我使用错误的args参数调用模块,argparse则会按预期正确地吐出一个错误,但不幸的是arparse随后调用sys.exit()又终止了外部 python 会话。

那不是我想要的。如何在不更改sys.exit()内部模块中的代码并且不将我的模块包装在代码中的情况下保护外部交互式 python 会话不被终止。- 我正在寻找可以设置的开关之类的东西,或者我可以在启动交互式 python 会话之前对其执行的操作,这样sys.exit()就不会终止它。

从评论更新:

我问这个问题的原因是emacs的python模式(python.el):它有效地“粘贴”了python会话中模块文件的完整代码。如果我想将它包装在 a 中,try..except我需要在包装它之前缩进整个模块并将其移交给 emacs 中的 python-session 缓冲区。

这是我使用的示例模块(我的大多数命令行实用程序都使用类似的模板):

#!/usr/bin/env python
"""\
tool to do stuff
"""
__author__ = """halloleo"""
__version__ = """0.1"""

import logging
import sys
import os

import clitools # my own helpers

#
# Options
#    
def argParser(locArgs = None):
    parser = clitools.HelpLogArgParser(description=__doc__)
    parser.add_argument('files', metavar='FILE', nargs='+',
                        help='file to work on')
    parser.add_loglevel_group()
    return parser.parse_args(locArgs)

def doStuff(file)
    # do stuff
    print file

#
# main
#
if __name__ == '__main__':

    args = argParser()     
    clitools.infoLoggerConfig(args.loglevel)
    logging.debug("args = %s" % args)          

    for f in args.files
        dostuff(f)

# Local Variables:
# leo-python-args-to-send: "--debug c:/tmp/testfile"
# End:

顺便说一句,我现在知道,这种方法有效。我已经实现了它,但是缩进整个模块代码有点吓人……这是我最后移交给 python 会话的内容:

import sys; sys.argv = '''scraper.py --debug c:/tmp/testfile'''.split()
try:
    #!/usr/bin/env python
    """\
    tool to do stuff
    """

    .
    .
    .

    # Local Variables:
    # leo-python-args-to-send: "--debug c:/tmp/testfile"
    # End:
except SystemExit, e:
    print "Terminated  with exit code", e
4

3 回答 3

4

使用try/except 块捕获SystemExit。例如:

import sys

try:
    sys.exit()
except SystemExit:
    print "Tried to sys.exit()"
于 2013-11-06T04:43:37.287 回答
2

如 python 的 sys 模块sys.exit中所述,执行以下操作:

退出 Python。这是通过引发SystemExit异常来实现的,因此由 try 语句的 finally 子句指定的清理操作会被兑现,并且可以在外部级别拦截退出尝试。

因此,您可以try except像处理任何其他异常一样处理块中的异常。


argparse实际上是sys.exitexit.argparse.ArgumentParser

argparse.ArgumentParser在某些情况下,子类化以引发更有意义的错误可能更值得:

import argparse
class BadCLIArgs(Exception):
    pass

class NonExitingArgumentParser(argparse.ArgumentParser):
    def exit(self, status=1, message=None):
        raise BadCLIArgs((status, message))

或者替代地覆盖errorexit也可能被称为--help标志。)

我从来没有真正喜欢 argparse 退出而不是引发更有意义的异常的方法。

于 2013-11-06T05:14:23.387 回答
0

我刚遇到这个问题。我使用时似乎引发了 SystemExit 错误

args = parser.parse_args(argv)

所以我的解决方案只是使用仅此行的 try-except :

def main(argv=None):
    ...
    try:
        args = parser.parse_args(argv)
    except SystemExit:
        return 0
    ...
    return 0

在我的脚本代码中,我使用:

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

这仍然在显示错误消息后在交互式 shell 中放置一个 0,但它确实成功地打印了错误消息并阻止交互式 shell 终止。

于 2014-09-08T06:35:49.703 回答