在冲突情况下 argparse 中变量的推断名称是什么

What's the inferred name of variables in argparse in conflicting cases

我注意到 argparse 使用相当 "mystic" 的方式在解析器中创建变量。我知道变量的名字通常很容易infer: 它是多头或空头选项的剥离版本(分别没有 ---)。

所有连字符 (-) 都变成下划线 (_) 成为合法的变量名。

但这给我留下了一个关于冲突案例的问题(我知道这是一个极端案例,但推断部分对我来说有点神秘)。例如程序:

import argparse
parser = argparse.ArgumentParser(description="A simple test about var names")
parser.add_argument("--max-value", type=int, help="the maximum value", metavar="Maximum-value")
parser.add_argument("-m", "--max_value", action="store_true", help="Whether to the use maximum value", dest="max1")
args = parser.parse_args()
print("max_value {}".format(args.max1))
print("max-value {}".format(args.max_value))

显然使用了两个非常相似的选项(--max-value--max_value),它们导致相同的推断变量 max_value。如果缺少任何一个选项,则变量将是 max_value 而不会产生歧义。

但是当两者都存在时,显然 --max_value 获得奖杯变量 max_value 而第二个 (--max-value) 得到什么?我一直没能找到第二个变量是什么。

所以,要访问它,我必须使用 dest 选项显式定义一个变量?如何获取可用变量名称的列表?有趣的是,如果我使用 dest= 作为 --max_value 选项,那么 --max-value 得到预期的变量 max_value--max_value 得到非推断的变量(在我的案例 max1)!

我也知道 metavar 与实际变量名无关,只影响帮助中的显示。

编辑:

添加来自@Martijn Pieters 回答的一些信息:

如果没有应用 dest,我将它写成解析器遵循一般规则,即应用隐式 dest。我的情况也是如此 dest="max_value".

所以,

parser.add_argument("--max-value", type=int, help="the maximum value")

完全相同:

parser.add_argument("--max-value", type=int, help="the maximum value", dest="max_value")

内部。

但是,下面的代码片段应该会产生不同的结果,但它不会:

# parserv1.py
import argparse
parser = argparse.ArgumentParser(description="A simple test about var names")
parser.add_argument("-m", "--max_value", action="store_true", help="Whether to the use maximum value", dest="max_value")
parser.add_argument("--max-value", type=int, help="the maximum value", metavar="Maximum-value", dest="max_value")
args = parser.parse_args()
print("max-value {}".format(args.max_value))

>>>python parserv1.py -m --max-value 3

max-value 3

# parserv2.py
import argparse
parser = argparse.ArgumentParser(description="A simple test about var names")
parser.add_argument("--max-value", type=int, help="the maximum value", metavar="Maximum-value", dest="max_value")
parser.add_argument("-m", "--max_value", action="store_true", help="Whether to the use maximum value", dest="max_value")
args = parser.parse_args()
print("max-value {}".format(args.max_value))

>>>python parserv1.py -m --max-value 3

max-value 3

两者都只是将 max_value 的值打印为 int,与它们声明的顺序无关。

那么,int 选项的优先级高于二进制(即标志)?在这些情况下选项类型重要吗?

P.S。 我正在使用 python 3.6.3,因为这可能是一个版本问题,所以我想提一下。

这里没有冲突;对于 --max-value--max_value,库只生成 完全相同的目的地名称 。写入相同 dest 目标名称的多个选项是完全有效的;在这种情况下,命令行上使用的最后一个选项获胜:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument("--option1", dest="foo")
_StoreAction(option_strings=['--option1'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>> parser.add_argument("--option2", dest="foo")
_StoreAction(option_strings=['--option2'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>> parser.parse_args(['--option2', 'bar', '--option1', 'baz'])
Namespace(foo='baz')

此处 --option1 baz 获胜,因为 --option1 最后在命令行中使用。

请注意,在命令行解析之前应用任何默认值; first 注册选项默认值获胜。然后解析命令行,如果只使用 一个 选项,那么与该选项关联的操作自然会获胜。

您可以选择不冲突的目标名称。不选择容易混淆的选项字符串也是一个好主意。

如果您正在寻找关于为给定的可选参数生成什么 dest 名称的正式规则集,请参阅 dest option documenation:

For optional argument actions, the value of dest is normally inferred from the option strings. ArgumentParser generates the value of dest by taking the first long option string and stripping away the initial -- string. If no long option strings were supplied, dest will be derived from the first short option string by stripping the initial - character. Any internal - characters will be converted to _ characters to make sure the string is a valid attribute name.


多个选项全部写入相同的 dest 目标名称对于支持给定选项的旧的、已弃用的名称很有用:

parser.add_argument('-n', '--new', dest='new', help="New hotness option")
# old name for the new hotness option, now deprecated but still supported
# argparse.SUPPRESS ensures it is no longer listed in the help output
parser.add_argument('-o', '--old', dest='new', help=argparse.SUPPRESS)

因此在命令行上使用-o--old与使用-n--new具有完全相同的效果;在命名空间上设置了相同的目标名称。