gpt4 book ai didi

python - 两个 argparse 参数可以是位置参数或可选参数

转载 作者:太空宇宙 更新时间:2023-11-03 14:03:50 25 4
gpt4 key购买 nike

我正在尝试使用 Python 3.5(Debian 9 附带的 Python 版本)编写一个程序,该程序采用两个命令行参数:输入文件名和输出文件名。

  • 输入文件名必须位于输出文件名之前,或者其本身前面带有 -i
  • 输出文件名是可选的。如果存在,以及输入文件name 前面不能有 -i,它必须跟在输入文件后面名称或其本身前面带有 -o

因此我想接受以下命令行:

programname.py infilename
programname.py -i infilename
programname.py infilename outfilename
programname.py -i infilename outfilename
programname.py infilename -o outfilename
programname.py -i infilename -o outfilename
programname.py outfilename -i infilename
programname.py -o outfilename -i infilename
programname.py -o outfilename infilename

使用消息可能如下所示:

programname.py [-i] infilename [[-o] outfilename]

但我无法从 documentation of the argparse module 看出如何在 add_argument() 的参数中表达这一点。当我为一个参数提供两个名称(一个是位置名称,一个是命名名称)时,add_argument() 会引发异常:

ValueError: invalid option string 'infilename': must start with a character '-'

我在 Stack Overflow 上搜索了类似的问题,发现 hpaulj's answer to Python argparse - mandatory argument - either positional or optionalhpaulj's answer to argparse: let the same required argument be positional OR optional 。这些答案中的构造使用一组两个互斥的参数,一个是位置参数,一个是命名参数。但它似乎不适用于多个此类参数。尝试使用以这种方式构建的解析器解析 -i infilename outfilename 会产生不同的异常:

argparse.ArgumentError: argument INFILE: not allowed with argument -i

但是,argparse本身无法打印此异常,甚至无法显示--help:

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
[8+ layers of method calls within `argparse.py` omitted]
File "/usr/lib/python3.5/argparse.py", line 396, in _format_actions_usage
start = actions.index(group._group_actions[0])
IndexError: list index out of range

已弃用的optparse模块将位置参数存储在单独的列表中,解析后运行的代码可以读取该列表来填充为None的每个参数。 argparse 中此列表的直接对应项是 parser.add_argument('args', nargs=argparse.REMAINDER)。调用 parse_args() 后手动处理位置参数是使用 argparse 接受上面显示的所有命令行形式的唯一方法吗?

#!/usr/bin/env python3
import argparse
import traceback

def mkparser1():
"""Raise an error.

ValueError: invalid option string 'infilename': must start with a character '-'
"""
parser = argparse.ArgumentParser()
parser.add_argument("infilename", "-i", metavar="INFILE")
parser.add_argument("outfilename", "-o", required=False, metavar="INFILE")
return parser

def mkparser2():
"""Do not raise an error but return an inadequate parser.

When asked -i infilename outfilename
"""
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("infilename", nargs="?", metavar="INFILE")
group.add_argument('-i', dest="infilename", metavar="INFILE")
group = parser.add_mutually_exclusive_group(required=False)
parser.add_argument("outfilename", nargs="?", metavar="OUTFILE")
parser.add_argument("-o", dest="outfilename", metavar="OUTFILE")
return parser

def test():
parser = mkparser2()
argstrings = [
"infilename",
"-i infilename",
"infilename outfilename",
"-i infilename outfilename",
"infilename -o outfilename",
"-i infilename -o outfilename",
"outfilename -i infilename",
"-o outfilename -i infilename",
"-o outfilename infilename",
"--help",
]
for s in argstrings:
print("for", s)
try:
pargs = parser.parse_args(s.split())
except Exception as e:
traceback.print_exc()
else:
print("infilename is %s and outfilename is %s"
% (pargs.infilename, pargs.outfilename))

if __name__=='__main__':
test()

最佳答案

您也许可以让您的程序接受可变数量的位置参数(0 到 2 之间),这些参数将被添加到位置参数列表中(使用 action="append"),并且还可以调用add_argument("-i",...)add_argument("-o",...) 用于处理标志等效项。

通常,argparse 选项属于位置类别或可选类别(但不能同时属于两者)。因此,您需要将设置传递给 argparse 以允许一些冗余,并在解析后处理冲突。例如,您可以将 argparse 配置为通过 -i INPUT 和位置 INPUT 接受输入文件,但然后在解析后添加自定义检查以确保只有一个使用了两种形式中的一种。

伪代码:


parser.add_argument('infile', metavar="INFILE", nargs='?',
type=argparse.FileType('r'),
action='append', dest="positional_args")
parser.add_argument('outfile', metavar="OUTFILE", nargs='?',
type=argparse.FileType('w'),
action='append', dest="positional_args")
parser.add_argument('-i', metavar="INFILE", dest="infile", default=None)
parser.add_argument('-o', metavar="OUTFILE", dest="outfile", default=None)

args = parser.parse_args([....])

# here insert check for conflicts between len(args.positional_args) and -i and -o
# example:
if sum([len(args.positional_args),
args.infile is not None,
args.outfile is not None]) != 2:
parser.print_help()
sys.exit(1)
...

infile = args.infile or args.positional_args.pop(0)
outfile = args.outfile or args.positional_args.pop(0)

关于python - 两个 argparse 参数可以是位置参数或可选参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49058396/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com