如何创建一个可选的参数?

时间:2013-07-17 18:16:14

标签: python command-line-arguments argparse

有没有办法让用户选择使用script.py --file c:/stuff/file.txt,而不是用户必须使用--file?所以相反,它看起来像script.py c:/stuff/file.txt但是解析器仍然知道用户正在引用--file参数(因为它是隐含的)。

5 个答案:

答案 0 :(得分:6)

试试这个

import argparse

class DoNotReplaceAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        if not getattr(namespace, self.dest):
            setattr(namespace, self.dest, values)

parser = argparse.ArgumentParser(description="This is an example.")
parser.add_argument('file', nargs='?', default='', help='specifies a file.', action=DoNotReplaceAction)
parser.add_argument('--file', help='specifies a file.')

args = parser.parse_args()
# check for file argument
if not args.file:
    raise Exception('Missing "file" argument')

查看帮助信息。所有参数都是可选的

usage: test.py [-h] [--file FILE] [file]

This is an example.

positional arguments:
  file         specifies a file.

optional arguments:
  -h, --help   show this help message and exit
  --file FILE  specifies a file.

有一点需要注意的是,位置file会覆盖可选--file并将args.file设置为默认值''。为了解决这个问题,我使用自定义action作为位置file。它禁止覆盖已经设置的属性。

要注意的另一件事是,而不是提出Exception,你可以指定默认值。

答案 1 :(得分:2)

如果我可以将您的问题重新解释为答案,那么您需要一个脚本,当运行时为:

  • script blahblah视为要打开的文件名
  • script --file blahblah视为要打开的文件名
  • script --file blah eggsblah视为要打开的文件名,eggs ......如何?
  • script blah eggs以不同的方式对待blah ...如何?

无论如何,我仍然从argparse开始:

#! /usr/bin/env python

import argparse

parser = argparse.ArgumentParser(description='script to morgle blahs')
parser.add_argument('--file', help='specify file name to be opened')
parser.add_argument('args', metavar='FILE', nargs='*')
args = parser.parse_args()

print args

此时运行./script.py -h会产生:

usage: script.py [-h] [--file FILE] [FILE [FILE ...]]

script to morgle blahs

positional arguments:
  FILE

optional arguments:
  -h, --help   show this help message and exit
  --file FILE  specify file name to be opened

附加运行:

$ ./script.py
Namespace(args=[], file=None)
$ ./script.py blah
Namespace(args=['blah'], file=None)
$ ./script.py --file blah eggs
Namespace(args=['eggs'], file='blah')
$ ./script.py blah eggs
Namespace(args=['blah', 'eggs'], file=None)

因此,现在您可以测试print argsargs.file(无None),然后检查--file,以及{是否args.args,而不仅仅是args.file {1}} None,您仍然可以查看args.args

如果在某些时候,您在自己的代码中决定某些参数组合是错误/无效的,您可以调用parser.error,例如:

if args.file is not None and len(args.args) > 0:
    parser.error('use [--file] <filename>, not --file <filename1> <filename2>')
if args.file is None and len(args.args) != 1:
    parser.error('use [--file] <filename>')

只需要一个参数,无论是否以--file字符串开头。

答案 2 :(得分:2)

要接受--file FILEFILE,您可以使用mutually_exclusive_group()

import argparse

parser = argparse.ArgumentParser(prog='script',
                                 description="This is an example.",
                                 usage='%(prog)s [-h] (--file FILE | FILE)')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('positional_file', nargs='?', help='specifies a file.')
group.add_argument('--file', help='specifies a file.')

args = parser.parse_args()
print(args)
filename = args.positional_file if args.file is None else args.file

Examples

['abc'] -> Namespace(file=None, positional_file='abc')

['--file', 'abc'] -> Namespace(file='abc', positional_file=None)

['--file', 'abc', 'def'] -> usage: script [-h] (--file FILE | FILE)
script: error: argument positional_file: not allowed with argument --file

[] -> usage: script [-h] (--file FILE | FILE)
script: error: one of the arguments positional_file --file is required

答案 3 :(得分:0)

您可以使用required=True中的argparse标记:

import argparse

parser = argparse.ArgumentParser(description="Describe stuff.")
parser.add_argument('--foo', required=True, help='bar')

然而,由于用户希望选项是可选的,因此this documentation says被认为是不好的形式,因为用户需要选项。

您可以改为定义所需的参数,然后将可选的--foo标志存储到此必需参数。这可能会导致解析器抛出异常,因为它可能认为您只是忽略了所需的参数。

import argparse

parser = argparse.ArgumentParser(description="Will this work?")
parser.add_argument('bar', help="required argument")
parser.add_argument('--foo', required=False, help="kind of required argument", dest='bar')

我认为最好的答案是没有一个必需的标志。只需要生成所需的变量,并在需要在程序中使用某些内容时为其定义默认值,但默认值适用于某种方式:

import argparse

parser = argparse.ArgumentParser(description="Other option.")
parser.add_argument('bar', default='value', help="required argument")

答案 4 :(得分:0)

在你的设计中,存在一个主要的模糊性(这已经是argparse未实现的原因的合理解释):

  • 如果在这种“双模”之后有更多的位置参数(例如,foo/--foobar),那么应该在像{{1}这样的cmdline中指定位置参数。 }?如果存在多个“双模式”args,这就变得更加混乱。

在我两年前编写的使用“双模”参数的脚本中,我完全禁止这样的输入,要求首先使用“位置模式”参数(如果有的话),然后是“命名模式”参数。

脚本在Perl中,我使用自定义逻辑在使用Perl的--foo=foo bar以“传递”模式解析其他选项(它通过任何无法识别的参数)后实现这一点。

所以我建议您使用ArgumentParser.parse_known_args()进行相同操作。