Argparse可选位置参数?

892
我有一个脚本,应该像这样使用:
usage: installer.py dir [-h] [-v]

dir 是一个位置参数,定义如下:

parser.add_argument('dir', default=os.getcwd())

我希望dir是可选的:当没有指定时,它应该默认为cwd
不幸的是,当我不指定dir参数时,会出现Error: Too few arguments的错误。
5个回答

1146

使用nargs='?'(如果只需要一个目录)或nargs='*'(如果需要多个目录)

parser.add_argument('dir', nargs='?', default=os.getcwd())

扩展示例:

>>> import os, argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('-v', action='store_true')
_StoreTrueAction(option_strings=['-v'], dest='v', nargs=0, const=True, default=False, type=None, choices=None, help=None, metavar=None)
>>> parser.add_argument('dir', nargs='?', default=os.getcwd())
_StoreAction(option_strings=[], dest='dir', nargs='?', const=None, default='/home/vinay', type=None, choices=None, help=None, metavar=None)
>>> parser.parse_args('somedir -v'.split())
Namespace(dir='somedir', v=True)
>>> parser.parse_args('-v'.split())
Namespace(dir='/home/vinay', v=True)
>>> parser.parse_args(''.split())
Namespace(dir='/home/vinay', v=False)
>>> parser.parse_args(['somedir'])
Namespace(dir='somedir', v=False)
>>> parser.parse_args('somedir -h -v'.split())
usage: [-h] [-v] [dir]

positional arguments:
  dir

optional arguments:
  -h, --help  show this help message and exit
  -v

33
在正则表达式中,?* 分别表示可选的0或1个字符和0或多个字符。请问在这里提到的 ?* 是否具有相同的含义?如果是,那么 + 是否也能用呢? - Dolan Antenucci
54
@dolan:是的,+ 也可以使用。详细信息请参见http://docs.python.org/2/library/argparse.html#nargs。 - Vinay Sajip
3
有没有办法让dir在可选参数中显示?或者似乎位置参数应该有一个前置的“可选”限定词。是否可以注册(就帮助而言)为这样的参数? - scagnetti
6
从上面可以看到,dir是可选的(在argparse输出中出现在方括号中表示这一点)。 - Vinay Sajip
5
这是更新后的(Python 3)文档 - 仔细阅读即可理解全部内容:https://docs.python.org/3/library/argparse.html#nargs。对于任何新手来说,如果想了解`argparse`模块,请从教程开始:https://docs.python.org/3/howto/argparse.html。 - Gabriel Staples
显示剩余2条评论

99
作为对@VinaySajip答案的补充。值得一提的是,还有其他值得注意的nargs选项
  1. parser.add_argument('dir', nargs=1, default=os.getcwd())

N(一个整数)。从命令行收集N个参数并组合成一个列表。

  1. parser.add_argument('dir', nargs='*', default=os.getcwd())

'*'。将所有存在的命令行参数收集到一个列表中。请注意,通常不会使用多个带有nargs =' * '的定位参数,但可以使用具有nargs =' * '的多个可选参数。

  1. parser.add_argument('dir', nargs='+', default=os.getcwd())

'+'。与'*'相同,将所有存在的命令行参数收集到一个列表中。此外,如果没有至少一个命令行参数存在,则会生成错误消息。

  1. parser.add_argument('dir', nargs=argparse.REMAINDER, default=os.getcwd())

argparse.REMAINDER。将剩余的所有命令行参数收集到一个列表中。这通常对于分派到其他命令行实用程序的命令行实用程序非常有用。

如果未提供nargs关键字参数,则使用的参数数量由操作确定。通常,这意味着将使用单个命令行参数并生成单个项目(而不是列表)。

编辑(从@Acumenus的评论中复制) nargs='?' 文档说:'?'。如果可能,将从命令行中消耗一个参数并作为单个项目生成。 如果没有命令行参数,则将生成默认值。


3
需要注意的是,nargs='?'并不会产生一个列表。 - Asclepius
@A-B-B 答案的最后一行是“通常这意味着将消耗一个单独的命令行参数,并且将生成一个单独的项目(而不是列表)。”希望这可以帮到你... - Matas Vaitkevicius
1
引用的那行代码是指没有定义 nargs 的情况,但 nargs='?' 正在定义它。文档中提到: '?'. 如果可能的话,将从命令行中消耗一个参数,并作为单个项目生成。如果没有命令行参数,则使用默认值生成值. - Asclepius
@A-B-B 如果您觉得有遗漏的地方,请编辑答案。谢谢。 - Matas Vaitkevicius
1
nargs=argparse.REMAINDERnargs='*'有什么区别?在我看来,它们的效果是相同的(在Python 2.7.10和Python 3.6.1中进行了测试),是否正确? - user8554766
请注意,为了使其正常工作,“default”是必需的。如果不指定默认值,则在该位置执行解析命令时,将会提示需要为该参数提供一个值。 - violet

20

简要回答

如前两个答案所示,您可以使用nargs='?'接受可选的位置参数。如果需要,您还可以将参数直接转换为Path类型,并将cwd缩短为.:

myfile.py

import argparse
import pathlib

parser = argparse.ArgumentParser()
parser.add_argument("dir", nargs="?", default=".", type=pathlib.Path)
parsed_args = parser.parse_args()

print("Installing to", parsed_args.dir.resolve())
$ python myfile.py
Installing to /users/myname/myfolder

$ python myfile.py /usr/bin/
Installing to /usr/bin

更详细的回答

既然你在问题中也提到了标志风格的True/False选项-h-v,那么这些例子可能会有用:

标志(例如-v

我们可以将不带参数的可选选项称为“标志”。对于标志,我们只关心它们是否被给出。 -h是argparse自动添加的标志(以及较长的版本--help),因此我们不应该覆盖它。如果我们考虑-v,则:

myfile.py

import argparse

parser = argparse.ArgumentParser()
parser.add_argument(
        "-v",
        "--version",
        action="store_true")
parsed_args = parser.parse_args()

if parsed_args.version:
    print("version flag given")
else:
    print("version flag not given")

请注意,add_argument() 的第二个参数是选项的更长名称。这不是强制性的,但它确实使您后续的代码更易读(例如使用 parsed_args.version 而不是 parsed_args.v),并使对您的安装程序的调用更加明确。

$ python myfile.py -v
version flag given

$ python myfile.py --version
version flag given

$ python myfile.py
version flag not given

可选参数(例如:--installdir /usr/bin/

有人可能会认为,在您的情况下,使用可选参数比位置参数更好。

myfile.py

import argparse
import pathlib

parser = argparse.ArgumentParser()
parser.add_argument(
        "-i",
        "--installdir",  # Optional (but recommended) long version
        type=pathlib.Path,
        default="/bin"
        )
parsed_args = parser.parse_args()

print("Installing to", parsed_args.installdir)
$ python myfile.py -i /usr/bin/
Installing to /usr/bin

$ python myfile.py --installdir /usr/bin/
Installing to /usr/bin

$ python myfile.py
Installing to /bin

0
import argparse
import os

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('-i', '--input', type=str, required=True, help='Input directory')
parser.add_argument('-o', '--output', type=str, required=True, help='Output directory')
parser.add_argument('-v', '--verbose', action='store_true', help='Enable verbose output')

args = vars(parser.parse_args())

input_dir = args['input']
output_dir = args['output']
verbose = args['verbose']

if verbose:
    print('Input directory:', input_dir)
    print('Output directory:', output_dir)

# Create the output directory and any necessary parent directories
os.makedirs(output_dir, exist_ok=True)

# Use input_dir and output_dir as needed

我使用vars()函数将parse_args()返回的Namespace对象转换为字典。这样可以通过字典键访问命令行参数,而不是单独的变量。
我还使用os.makedirs()而不是os.mkdir()来创建输出目录,并传递exist_ok=True参数以避免在目录已经存在时引发错误。这可以使您的代码更加高效和健壮。

OP在询问位置参数是否可选,而不是如何访问这些参数,并且他们没有提到任何关于创建目录的内容,所以我不确定这个回答是否符合他们的问题。 - bjg222

-12

parser.add_argument 还有一个开关 required。您可以使用 required=False。 以下是 Python 2.7 的示例片段:

parser = argparse.ArgumentParser(description='get dir')
parser.add_argument('--dir', type=str, help='dir', default=os.getcwd(), required=False)
args = parser.parse_args()

18
OP 询问的是位置参数,而不是 '--dir'。'required' 不是位置参数的有效参数。而 'false' 只是一个打字错误,她实际上想表达的是 'False'。对于新手 +1,对于粗心的人 -1。 - SoloPilot
1
我们不能在位置参数中使用 required - Karthik Sunil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接