【问题标题】:Specifying default filenames with argparse, but not opening them on --help?使用 argparse 指定默认文件名,但不在 --help 上打开它们?
【发布时间】:2016-10-23 04:32:24
【问题描述】:

假设我有一个对文件执行某些操作的脚本。它在命令行上使用此文件的名称,但如果未提供,则默认为已知文件名(例如content.txt)。使用 python 的argparse,我使用以下内容:

parser = argparse.ArgumentParser(description='my illustrative example')
parser.add_argument('--content', metavar='file', 
                     default='content.txt', type=argparse.FileType('r'),
                     help='file to process (defaults to content.txt)')
args = parser.parse_args()
# do some work on args.content, which is a file-like object

这很好用。唯一的问题是,如果我运行python myscript --help,如果文件不存在,我会得到ArgumentError(我想这是有道理的),并且没有显示帮助文本。如果用户只想要--help,我宁愿它不要尝试打开文件。有没有办法做到这一点?我知道我可以将参数设置为字符串,然后自己处理打开文件(我一直在这样做),但让 argparse 处理它会很方便。

【问题讨论】:

  • 好吧,看来您必须在这里做出决定。您可以使默认文件可用(因为它是“默认”),也可以按照您自己的建议自行打开文件。或者,您似乎可以使用标准输入作为默认值,但是您将无法指定默认文件名,如果您不想填充该文件,这可能不是一个坏选择。
  • FWIW 这显然已在足够新的 Python 版本中修复,您提供的 sn-p 工作正常。

标签: python argparse


【解决方案1】:

你可以继承argparse.FileType:

import argparse
import warnings

class ForgivingFileType(argparse.FileType):
    def __call__(self, string):
        try:
            super(ForgivingFileType,self).__call__(string)
        except IOError as err:
            warnings.warn(err)

parser = argparse.ArgumentParser(description='my illustrative example')
parser.add_argument('--content', metavar='file', 
                     default='content.txt', type=ForgivingFileType('r'),
                     help='file to process (defaults to content.txt)')
args = parser.parse_args()

无需接触 ArgumentParser._parse_known_args 等私有方法即可工作。

【讨论】:

    【解决方案2】:

    查看argparse代码,我明白了:

    • ArgumentParser.parse_args 调用 parse_known_args 并确保没有任何待解析的参数。
    • ArgumentParser.parse_known_args 设置默认值并调用 ArgumentParser._parse_known_args

    因此,解决方法是直接使用ArgumentParser._parse_known_args 检测-h,然后照常使用ArgumentParser.parse_args

    import sys, argparse
    parser = argparse.ArgumentParser(description='my illustrative example', argument_default=argparse.SUPPRESS)
    parser.add_argument('--content', metavar='file',
                         default='content.txt', type=argparse.FileType('r'),
                         help='file to process (defaults to content.txt)')
    parser._parse_known_args(sys.argv[1:], argparse.Namespace())
    args = parser.parse_args()
    

    请注意,ArgumentParser._parse_known_args 需要几个参数:来自命令行的参数和命名空间。

    当然,我不推荐这种方法,因为它利用了内部的argparse 实现,并且将来可能会改变。不过,我不觉得它太乱,所以如果你认为维护风险得到回报,你仍然可能想使用它。

    【讨论】:

    • 似乎没有一个很好的解决方案,但这对于一次性脚本来说是可行的。谢谢!
    【解决方案3】:

    默认使用标准输入:

    parser.add_argument('file', default='-', nargs='?', type=argparse.FileType('r'))
    

    【讨论】:

      【解决方案4】:

      也许您可以在检查文件是否存在的add_argument 调用中定义自己的typeaction,如果存在则返回文件句柄,否则返回None(或其他内容)。

      这需要你自己编写一些代码,但如果不能总是使用默认值,你可能迟早要做一些检查。就像 Manny D 认为的那样,您可能需要重新考虑您的默认值。

      【讨论】:

        猜你喜欢
        • 2012-08-22
        • 1970-01-01
        • 2021-07-02
        • 1970-01-01
        • 2019-11-20
        • 1970-01-01
        • 1970-01-01
        • 2020-10-14
        相关资源
        最近更新 更多