无法让 argparse 读取带有破折号的引号字符串?

2025-03-04 08:24:00
admin
原创
86
摘要:问题描述:有没有办法让 argparse 将两个引号之间的任何内容识别为单个参数?它似乎一直看到破折号,并假设它是新选项的开始我有类似的东西:mainparser = argparse.ArgumentParser() subparsers = mainparser.add_subparsers(dest='...

问题描述:

有没有办法让 argparse 将两个引号之间的任何内容识别为单个参数?它似乎一直看到破折号,并假设它是新选项的开始

我有类似的东西:

mainparser = argparse.ArgumentParser()
subparsers = mainparser.add_subparsers(dest='subcommand')
parser = subparsers.add_parser('queue')
parser.add_argument('-env', '--extraEnvVars', type=str,
                        help='String of extra arguments to be passed to model.')
...other arguments added to parser...

但是当我跑步时:

python Application.py queue -env "-s WHATEVER -e COOL STUFF"

它给了我:

Application.py queue: error: argument -env/--extraEnvVars: expected one argument

如果我省略第一个破折号,它完全可以正常工作,但能够传入带有破折号的字符串至关重要。我尝试使用 \ 对其进行转义,这使其成功,但将 \ 添加到参数字符串中 有人知道如何解决这个问题吗?无论 -s 是否是解析器中的参数,都会发生这种情况。

编辑:我正在使用 Python 2.7。

编辑2:

python Application.py -env " -env"

运行良好,但是

python Application.py -env "-env"

没有。

EDIT3:看起来这实际上是一个正在讨论的错误:http://www.gossamer-threads.com/lists/python/bugs/89529,http : //python.6.x6.nabble.com/issue9334-argparse-does-not-accept-options-taking-arguments-beginning-with-dash-regression-from-optp-td578790.html。它只存在于 2.7 中,而不存在于 optparse 中。

EDIT4:当前打开的错误报告是:http://bugs.python.org/issue9334


解决方案 1:

更新答案:

调用它时你可以放置一个等号:

python Application.py -env="-env"

原始答案:

我也遇到过你尝试做的事情,但 argparse 中有一个解决方法,即parse_known_args方法。这将允许所有未定义的参数通过解析器,并假设你会将它们用于子进程。缺点是,如果参数不正确,你不会收到错误报告,并且你必须确保你的选项和子进程的选项之间没有冲突。

另一种选择是强制用户使用加号而不是减号:

python Application.py -e "+s WHATEVER +e COOL STUFF"

然后在传递到子进程之前,在后期处理中将“+”更改为“-”。

解决方案 2:

这个问题在http://bugs.python.org/issue9334中有深入讨论。大部分活动发生在 2011 年。我去年添加了一个补丁,但argparse补丁积压了相当多。

问题在于像 这样的字符串可能存在歧义'--env',或者"-s WHATEVER -e COOL STUFF"当它跟在带有参数的选项后面时。

optparse执行从左到右的简单解析。第一个--env是接受一个参数的选项标志,因此它会使用下一个参数,而不管它看起来如何。 argparse另一方面,它会循环两次遍历字符串。首先,它会将它们分类为“O”或“A”(选项标志或参数)。在第二次循环中,它会使用它们,使用re类似的模式匹配来处理变量nargs值。在这种情况下,我们似乎有OO两个标志,但没有参数。

使用时的解决方案argparse是确保参数字符串不会与选项标志混淆。这里(以及在错误问题中)显示的可能性包括:

--env="--env"  # clearly defines the argument.

--env " --env"  # other non - character
--env "--env "  # space after

--env "--env one two"  # but not '--env "-env one two"'

本身'--env'看起来像一个标志(即使加引号,请参阅sys.argv),但当其后跟其他字符串时则不是。但它"-env one two"存在问题,因为它可以被解析为['-e','nv one two'],即“-e”标志后跟一个字符串(或更多选项)。

--并且nargs=argparse.PARSER还可用于强制argparse将所有后续字符串视为参数。但它们仅在参数列表末尾起作用。

在 issue9334 中有一个建议的补丁来添加一种args_default_to_positional=True模式。在此模式下,解析器仅当能够明确地将字符串与定义的参数匹配时,才会将其归类为选项标志。因此,'--env --one' 中的 '--one' 将被归类为参数。但 '--env --env' 中的第二个 '--env' 仍将被归类为选项标志。


扩展相关案例

使用 argparse 和以破折号(“-”)开头的参数值

parser = argparse.ArgumentParser(prog="PROG")
parser.add_argument("-f", "--force", default=False, action="store_true")
parser.add_argument("-e", "--extra")
args = parser.parse_args()
print(args)

生产

1513:~/mypy$ python3 stack16174992.py --extra "--foo one"
Namespace(extra='--foo one', force=False)
1513:~/mypy$ python3 stack16174992.py --extra "-foo one"
usage: PROG [-h] [-f] [-e EXTRA]
PROG: error: argument -e/--extra: expected one argument
1513:~/mypy$ python3 stack16174992.py --extra "-bar one"
Namespace(extra='-bar one', force=False)
1514:~/mypy$ python3 stack16174992.py -fe one
Namespace(extra='one', force=True)

“-foo one” 案例失败,因为-foo被解释为标志加上未指定的附加项。这与允许被解释为 的-f操作相同。-fe`['-f','-e']`

如果我将 更改nargsREMAINDER(不是PARSER),则之后的所有内容都-e将被解释为该标志的参数:

parser.add_argument("-e", "--extra", nargs=argparse.REMAINDER)

所有情况都适用。请注意,该值是一个列表。不需要引号:

1518:~/mypy$ python3 stack16174992.py --extra "--foo one"
Namespace(extra=['--foo one'], force=False)
1519:~/mypy$ python3 stack16174992.py --extra "-foo one"
Namespace(extra=['-foo one'], force=False)
1519:~/mypy$ python3 stack16174992.py --extra "-bar one"
Namespace(extra=['-bar one'], force=False)
1519:~/mypy$ python3 stack16174992.py -fe one
Namespace(extra=['one'], force=True)
1520:~/mypy$ python3 stack16174992.py --extra --foo one
Namespace(extra=['--foo', 'one'], force=False)
1521:~/mypy$ python3 stack16174992.py --extra -foo one
Namespace(extra=['-foo', 'one'], force=False)

argparse.REMAINDER类似于 '*',只不过它会接受后面的所有内容,无论它是否看起来像标志。 argparse.PARSER更像 '+',因为它positional首先需要一个类似的参数。它是使用nargssubparsers

这个用途REMAINDER是有记录的,https://docs.python.org/3/library/argparse.html#nargs

解决方案 3:

您可以使用空格开始参数,python tst.py -e ' -e blah'这是一个非常简单的解决方法。lstrip()如果您愿意,只需选择将其恢复正常即可。

或者,如果第一个“子参数”不是原始函数的有效参数,那么您根本不需要执行任何操作。也就是说,python tst.py -e '-s hi -e blah'不起作用的唯一原因是因为-s是 的有效选项tst.py

此外,现在已弃用的optparse模块仍可正常运行。

解决方案 4:

我已经将一个脚本从 optparse 移植到 argparse,其中某些参数的值可以以负数开头。我遇到这个问题是因为该脚本在许多地方使用时没有使用“=”符号将负值连接到标志。在阅读了此处和http://bugs.python.org/issue9334中的讨论后,我知道参数只接受一个值,并且接受后续参数(即缺失值)作为值没有任何风险。FWIW,我的解决方案是预处理参数,并在传递给 parse_args() 之前用“=”连接有问题的参数:

def preprocess_negative_args(argv, flags=None):
    if flags is None:
        flags = ['--time', '--mtime']
    result = []
    i = 0
    while i < len(argv):
        arg = argv[i]
        if arg in flags and i+1 < len(argv) and argv[i+1].startswith('-'):
            arg = arg + "=" + argv[i+1]
            i += 1
        result.append(arg)
        i += 1
    return result

这种方法至少不需要任何用户更改,它只修改明确需要允许负值的参数。

>>> import argparse
>>> parser = argparse.ArgumentParser("prog")
>>> parser.add_argument("--time")
>>> parser.parse_args(preprocess_negative_args("--time -1d,2".split()))
Namespace(time='-1d,2')

告诉 argparse 哪些参数应该明确允许以破折号开头的值会更方便,但这种方法似乎是一个合理的折衷方案。

解决方案 5:

类似的问题。我通过将空格替换为“\”来解决这个问题。例如:

替换

python Application.py "cmd -option"

python Application.py "cmd -option"

不确定是否适合您的问题。

解决方案 6:

paser.add_argument("--argument_name", default=None, nargs=argparse.REMAINDER)

python_file.py --参数名称“--abc=10 -a=1 -b=2 cdef”

注意:参数值只能在双引号内传递,单引号则不行

解决方案 7:

为了避免必须处理 argparse,即使查看不是您想要的标志的“-”,您可以在 argparse 读取它之前编辑 sys.argv。只需保存您不想看到的参数,将填充参数放在它的位置,然后在 argparse 处理 sys.argv 之后将填充参数替换为原始参数。我只是必须为自己的代码执行此操作。它并不漂亮,但它有效并且很容易。如果您的标志不总是按相同的顺序排列,您还可以使用 for 循环遍历 sys.argv。

parser.add_argument('-n', '--input', nargs='*')
spot_saver = ''
if sys.argv[1] == '-n':             #'-n' can be any flag you use
    if sys.argv[2][0] == '-':       #This checks the first character of the element
        spot_saver = sys.argv[2] 
        sys.argv[2] = "fillerText" 
args = parser.parse_args()
if args.input[0] == 'fillerText':
    args.input[0] = spot_saver

解决方案 8:

不确定较新的 Python 版本怎么样,但在 3.6.8 中我做了类似的事情:

parser.add_argument('--eat-args',
                    type=str, 
                    nargs='+',
                    action=EatArgsAction)

EatArgsAction看起来像

class ToDistCpAction(argparse.Action):
  """
  Turns all `"` or `'` into `` (nothing).
  """
  def __call__(self, parser, namespace, values, option_string) -> None:
    setattr(namespace, self.dest, ' '.join(map(lambda arg: re.sub(r'(?<!w)(+)', '-', arg), values)))

并且这可以吃掉传递的参数,例如:++eat-args +p +I +whatever+anything

你会得到--eat-args -p -I -whatever+anything

编辑:@tripleee 谴责后进行了更改

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3911  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2721  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   61  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   61  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   54  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用