有script.py --file c:/stuff/file.txt
没有办法让用户有选择地使用--file
?因此,它看起来像script.py c:/stuff/file.txt
,但解析器仍然知道用户指的是 --file 参数(因为它是隐含的)。
5 回答
尝试这个
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.
需要注意的一件事是 positionalfile
将覆盖 optional--file
并设置args.file
为默认 ''。为了克服这个问题,我将 customaction
用于 positional file
。它禁止覆盖已经设置的属性。
Exception
要注意的另一件事是,您可以指定默认值,而不是提高。
要接受一个--file FILE
或一个FILE
,你可以使用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
例子
['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
如果我可以将您的问题改写为答案,那么您需要一个脚本,该脚本在运行时为:
script blah
视为blah
要打开的文件名script --file blah
视为blah
要打开的文件名script --file blah eggs
视为blah
要打开的文件名,并且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 args
现在您可以测试是否args.file
是None
(否--file
)然后检查,而不是args.args
简单地检查,如果args.file
不是,您仍然可以检查。 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
字符串。
您可以required=True
在以下位置使用标志argparse
:
import argparse
parser = argparse.ArgumentParser(description="Describe stuff.")
parser.add_argument('--foo', required=True, help='bar')
但是,正如本文档所述,将选项设为必需被认为是错误的形式,因为用户希望选项是可选的。
您可以改为定义所需参数,然后将可选--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")
在您的设计中,存在一个主要的歧义(这已经是一个合理的解释,为什么它不是由 实现的argparse
):
- 如果在这样的“双模式”之后还有更多的位置参数(例如,
foo/--foo
和bar
),那么在命令行中应该将位置参数分配给哪个位置参数,例如--foo=foo bar
?如果有多个“双模式”参数,这会变得更加混乱。
在我两年前编写的使用“双模式”参数的脚本中,我完全禁止此类输入,要求“位置模式”参数(如果有)首先出现,然后是“命名模式”参数。
该脚本在 Perl 中,在使用 PerlGetopt::Long
在“传递”模式下解析其他选项后,我使用自定义逻辑来实现这一点(它传递任何无法识别的参数)。
所以我建议你也这样做,使用ArgumentParser.parse_known_args()
.