Argparse 可选的位置参数?

906 投票
4 回答
447277 浏览
提问于 2025-04-16 08:43

我有一个脚本,应该这样使用:

usage: installer.py dir [-h] [-v]

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

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

我希望 dir 是可选的:当没有指定时,它应该默认为 cwd

不幸的是,当我不指定 dir 参数时,我会收到 Error: Too few arguments 的错误信息。

4 个回答

24

简短回答

正如之前的两个回答所示,你可以使用 nargs='?' 来接受一个可选的位置参数。如果你想的话,也可以直接把这个参数变成 Path 类型,或者把当前工作目录缩短为 .

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

详细回答

因为你在问题中提到了像 -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.versionparsed_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
100

这是对@VinaySajip回答的补充。这里有一些额外的 nargs 选项值得一提

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

N(一个整数)。从命令行获取N个参数,这些参数会被放到一个列表里。

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

'*'。所有在命令行中出现的参数都会被放到一个列表里。注意,通常来说,使用 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='?' 文档中说:'?'。如果可能的话,会从命令行消耗一个参数,并作为单独的项目返回。如果没有命令行参数,默认值会被返回。

1168

使用 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

撰写回答