使用不需要指定输出文件名的可选参数运行 argparse

Posted

技术标签:

【中文标题】使用不需要指定输出文件名的可选参数运行 argparse【英文标题】:Running argparse with optional arguments that won't require specifying output filename 【发布时间】:2021-09-29 02:14:10 【问题描述】:

我已经阅读了一堆已经回答的问题,但我没有看到这些问题 - 至少不是我认识的。

我正在使用 argparse 获取文件并将其转换为不同的类型。输入文件名是必需的。不需要输出文件名,因为可选参数应该处理它。到目前为止的代码如下:

import sys
import argparse
parser = argparse.ArgumentParser(description='Convert file to new type')
parser.add_argument('--json', type=str, help='Converts to json format')
parser.add_argument('--bibtex', type=str, help='Converts to bibtex format')
parser.add_argument('--html', type=str, help='Converts to html format')
parser.add_argument('inputfilename', type=str, help='enter the original filename')
args = parser.parse_args()
filename=args.filename
if args.json:
    print('Converting to json ...')
    #conversion code here
elif args.bibtex:
    print('Converting to bibtex ...')
    #conversion code here
elif args.html:
    print('Converting to html ...')
    #conversion code here
else:
    print('No conversion type indicated')

问题是每当我使用这些标志之一。如果我这样做了

$ ./orsconvert.py --json inputfilename

我收到一个错误提示

orsconvert.py: error: the following arguments are required: inputfilename

它这样做是因为它将提供的inputfilename 解释为连接到--json 的输出文件名。它试图强迫我在可选参数之后和输入文件名之前实际声明输出文件名,类似于:

$ ./orsconvert.py --json outputfilename inputfileneame

但是,如果有办法解决,我不想这样做。我希望它接受--json 作为指示,然后使用inputfilename 作为输入并根据代码指定的内容自动将其保存为outputfilename

是的,我正在考虑将 3 个可选参数设为一组以简化代码......但这仍然没有解释如何让它在可选参数之后和最终 inputfilename 之前不需要另一个参数必需的参数。

我还可以在parser.add_argument('...') 字段中添加其他内容,从而不再要求我指定outputfilename?我想尽可能少地更改代码,因为我已经突破了我的编码理解的极限。

【问题讨论】:

我不确定设置是否正确。在我看来,您真正想要的是 1-2 个文件名和一个“模式”,而不是 1 个文件名、一个“模式”和一个可选的“模式文件名”。这应该是模式的选择/子解析器、位置文件名和nargs="?" 文件名。 你不能有可选的输出文件名作为它自己的参数,以及类型的布尔标志(忽略如果指定了多个类型会发生什么)? 【参考方案1】:

问题在于您将--json 定义为需要一个参数,并且它将输入文件名作为该参数。您的三个转换器应该使用store_true 操作,而不是默认的store 操作。

parser = argparse.ArgumentParser(description='Convert file to new type')
parser.add_argument('--json', action='store_true', help='Converts to json format')
parser.add_argument('--bibtex', action='store_true', help='Converts to bibtex format')
parser.add_argument('--html', action='store_true', help='Converts to html format')
parser.add_argument('inputfilename', help='enter the original filename')
args = parser.parse_args()

通过此更改,args.json 等都是您期望的布尔值。 store_true 操作负责将类型定义为bool,并将默认值定义为false


不过,更好的是,一个必需的位置参数必须取值jsonbibtexhtml。然后parse_args 本身会检测是否给出了不正确或缺少的转换类型。

parser = argparse.ArgumentParser(description='Convert file to new type')
parser.add_argument('inputfilename', help='enter the original filename')
parser.add_argument('conversion_type', choices=['json', 'bibtex', 'html'])
args = parser.parse_args()
filename = args.filename
conversion_type = args.conversion_type  # Guaranteed to be json, html, or bibtex
if conversion_type == "json":
    ...
elif conversion_type == "bibtex":
    ...
elif conversion_type == "html":

如果您想要一个带有 default 值的选项,请系好安全带 :) 我们将添加 4 选项:一个允许明确指定输出类型的选项,以及三个设置快捷方式。

p = argparse.ArgumentParser()
p.add_argument('inputfilename')
p.add_argument('--type', choices=['json', 'bibtex', 'html'], default='json')
p.add_argument('--json', action='store_const', const='json', dest='type')
p.add_argument('--html', action='store_const', const='html', dest='type')
p.add_argument('--bibtex', action='store_const', const='bibtex', dest='type')

--json--bibtex--html 分别与 --type json--type bibtex--type html 具有相同的效果。和以前一样,--type 只能将这三个值作为其参数。如果超过一个,最后使用的一个生效。

【讨论】:

谢谢。这有帮助。我没有意识到使用 -- 默认情况下将变量设为可选会使其需要另一个参数。 仅默认 :) 让我们退后一步。使用 -- 前缀参数名称使其成为一个选项,而不是位置参数。但是,每个选项都有一个关联的action,默认情况下是'store'。如果使用该选项,则存储操作使该选项需要一个参数。另一方面,'store_const' 不需要 需要参数,因为您提供的值要预先存储在参数定义中。 好的,所以从实际的角度来看,我为什么要使用 'store_true' 而我为什么要使用 'store_const'?我喜欢 'choices=[...]' 的想法,但我的主管希望我保留带有连字符 '--json'、'--bibtex'、'--html' 的字段,即使至少需要一个。 store_true 基本上是store_const 的一个特例。 add_argument("...", action='store_true')add_argument("...", action='store_const', const=True, type=bool, default=False) 的缩写。 (也有相应的store_false 操作。) 您可能还想查看docs.python.org/3/library/argparse.html#mutual-exclusion,它可以确保选择三个选项中的一个,就像choices 用于单个选项或参数一样。【参考方案2】:

argparse 已经提供了您实际拥有所需 API 所需的一切,而不是您认为需要的 API。

类型应该是几个choices 之一,而不是三个单独的标志。 inputfilename 应该是必需的。 outputfilename 应该是可选的。
import argparse
parser = argparse.ArgumentParser(description='Convert file to new type')
parser.add_argument('format', choices=["json", "bibtex", "html"])
parser.add_argument('inputfilename', type=str)
parser.add_argument('outputfilename', type=str, nargs="?")
args = parser.parse_args()
print(args)

这会自动提供所需的用法,不会误用可选项,而是获得错误处理。

$ ./converter json in.txt
Namespace(format='json', inputfilename='in.txt', outputfilename=None)
$ ./converter html in.txt out.html
Namespace(format='html', inputfilename='in.txt', outputfilename='out.html')
$ ./converter yaml in.txt         
usage: converter [-h] json,bibtex,html inputfilename [outputfilename]
converter: error: argument format: invalid choice: 'yaml' (choose from 'json', 'bibtex', 'html')

【讨论】:

对不起,不是故意偷你的答案;我想它是在我添加同样的建议时出现的。 @chepner 至少我们没有选择相同的参数顺序。 ;) 很想偷那个:)【参考方案3】:

您的问题是 argparse 需要输入,特别是因为您有 type=str

尝试用这个替换 json arg

parser.add_argument('--json', action="store_true", help='Converts to json format')

【讨论】:

【参考方案4】:

所以问题看起来好像每个 argparse.arg 都需要指定一个参数,无论是什么。所以你可以将它设置为布尔值。但我认为这种方法可能会更好:

import sys
import argparse
parser = argparse.ArgumentParser(description='Convert file to new type')
parser.add_argument('--type', type=str, help='Converts to any of the following formats: 1 for json, 2 for bibtex and 3 for html')
parser.add_argument('--inputfilename', type=str, help='enter the original filename')
args = parser.parse_args()
filename=args.inputfilename
if args.type:
    conversion_type = int(args.type)
    if conversion_type == int(1):
        print('Converting to json ...')
        #conversion code here
    elif conversion_type == 2:
        print('Converting to bibtex ...')
        #conversion code here
    elif conversion_type == 3:
        print('Converting to html ...')
        #conversion code here
else:
    print('No conversion type indicated')

只需添加一个参数来指定类型。在此基础上,根据条件转换或不转换。

【讨论】:

我认为typeinputfilename 不应该是可选的。 Argparse 已经支持选择,因此使用一些不透明的编号方案(严重混淆类型)也不太合适。 猜猜我不知道action=store_true 选项。如果我的回答具有误导性,我们深表歉意。 @MisterMiyagi 我想这是真的

以上是关于使用不需要指定输出文件名的可选参数运行 argparse的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript中的可选参数[重复]

WCF中UriTemplate中的可选参数

Odoo 14 CE 中的可选依赖项

Moya任务中的可选参数

PHP函数中的可选参数不考虑顺序

qt creator源码全方面分析(2-3)