如何根据位置参数的值设置argparse以排除可选参数

2 投票
1 回答
2691 浏览
提问于 2025-04-17 22:46

这个参数包含一个动作字段和一些可选的开关,这些开关可以改变动作的行为。

下面是argparse的代码示例:

parser=argparse.ArgumentParser()
parser.add-argument('action',metavar='action', choices=['analysis','report','update'],nargs='?', default='report')
parser.add-argument('-d',dest='delay',type=int, choices=range(1,10),default=1)
parser.add-argument('-v',dest='verbose',action='store-true',default=False)
parser.add-argument('-o',dest='offline',action='store-true',default=False)
parser.add-argument('-n',dest='names',required=False)

我想让开关选项 -o、-d、-v 只在动作为 report 时可用,而选项 -n 只在动作为 analysis 时可用。

我知道有一个互斥组的设置,但这个设置只是针对参数,而不是针对参数的值!

顺便问一下,argparse 支持组合选项吗,比如 -vo...???

1 个回答

2

首先:是的,像 -vo 这样的组合选项是支持的。

接下来谈谈如何切换动作:在你的 ArgumentParser 中添加一个子解析器正是你想要做的事情。可以查看文档中关于 15.4.5.1. 子命令 的部分,那里详细解释了相关内容,并且有示例。

编辑:我现在参考你在这篇帖子下的评论:如果你在程序调用时没有提供子命令参数,解析器通常会给你一个友好的提示,告诉你如何使用这个程序,然后以“参数太少”错误退出。我重写了你的代码来展示这一点。

test.py

import argparse
parser=argparse.ArgumentParser()

subparsers = parser.add_subparsers(help='sub-command help')

parser_analysis = subparsers.add_parser('analysis', help='analysis help text')
parser_analysis.add_argument('-n',dest='names',required=False)

parser_report = subparsers.add_parser('report', help='report help text')
parser_report.add_argument('-d',dest='delay',type=int, choices=range(1,10),default=1)
parser_report.add_argument('-v',dest='verbose',action='store_true',default=False)
parser_report.add_argument('-o',dest='offline',action='store_true',default=False)

parser_update = subparsers.add_parser('update', help='update help text')
parser.parse_args()

现在来看一下用不同参数调用这个 test.py 的情况:

$python test.py
usage: test.py [-h] {analysis,report,update} ...
test.py: error: too few arguments
$python test.py -h
usage: test.py [-h] {analysis,report,update} ...

positional arguments:
  {analysis,report,update}
                        sub-command help
    analysis            analysis help text
    report              report help text
    update              update help text

optional arguments:
  -h, --help            show this help message and exit
$python test.py report -h
usage: test.py report [-h] [-d {1,2,3,4,5,6,7,8,9}] [-v] [-o]

optional arguments:
  -h, --help            show this help message and exit
  -d {1,2,3,4,5,6,7,8,9}
  -v
  -o

所以我认为唯一的问题是,当你调用 python test.py 而没有任何子命令时,程序会抛出一个错误。因此,我会做一些类似这样的事情:

try:
  args=parser.parse_args()
except:
  exit(0)

这样可以避免用户看到未处理的错误。这样你就能得到和 svn 命令一样的行为。

如果你想处理成执行一个默认的子命令,你需要做一些类似于这个帖子回答中提到的事情:

Argparse - 如何指定默认子命令

import sys
#...your parser definitions
if (len(sys.argv) < 2):
    args = parser.parse_args(['update'])
else:
    args = parser.parse_args()

如果 sys.argv 中的参数列表少于 2,这将解析一个命令 update。为什么是 2?因为参数列表中的第一个参数总是你调用的程序,比如 test.py

问题是,你真的想要这样的行为吗?因为如果我可以随时调用 test.py,就没有必要调用 test.py update,所以用户可能会变得懒惰,根本不使用 test.py update 命令。此外,如果你以后想要不同的默认行为,比如 test.py 启动交互模式,习惯于调用 test.py 来更新的用户可能会感到困惑,或者他们使用你程序的脚本会出错。

撰写回答