Docopt:重复元素后的选项被解释为重复元素

时间:2014-02-15 21:56:05

标签: python docopt

我在我的简单Python程序中使用 docopt

#!/usr/bin/env python
"""
Farmers market

Usage:
  farmersmarket.py buy -i <item> -q <quantity> [<quantity>] [-p <price>] [-dvh]
  farmersmarket.py -d | --debug
  farmersmarket.py -v | --version
  farmersmarket.py -h | --help

Options:
  -i --item         Item.
  -q --quantity     Quantity.
  -p --price        Price.
  -d --debug        Show debug messages.
  -h --help         Show this screen.
  -v --version      Show version.
"""

from docopt import docopt

print docopt(__doc__)

如果我跑:

farmersmarket.py buy --item eggs --quantity 100 115 --price 0.25

预期的行为是以0.25的价格在价值100和115之间购买随机数量的鸡蛋。至少在解释参数时,这没有问题。换句话说, docopt 可以按预期获得所有内容:

{'--debug': False,
 '--help': False,
 '--item': True,
 '--price': True,
 '--quantity': True,
 '--version': False,
 '<item>': 'eggs',
 '<price>': '0.25',
 '<quantity>': ['100', '115'],
 'buy': True}

然而,有时我不想购买随机数量的鸡蛋,但需要特定数量的鸡蛋。在这种情况下,--quantity选项只接受一个参数:

farmersmarket.py buy --item eggs --quantity 471 --price 0.25

但由于 docopt --price 0.25解释为--quantity的重复元素并失去<price>的值,因此失败了:

{'--debug': False,
 '--help': False,
 '--item': True,
 '--price': True,
 '--quantity': True,
 '--version': False,
 '<item>': 'eggs',
 '<price>': None,
 '<quantity>': ['471', '0.25'],
 'buy': True}

如何在重复元素后获得其他选项?

1 个答案:

答案 0 :(得分:11)

实际上,您忘记将<price>参数添加到Options:描述部分;以下代码:

#!/usr/bin/env python
"""
Farmers market

Usage:
  farmersmarket.py buy -i <item> -q <quantity> [<quantity>] [-p <price>] [-dvh]
  farmersmarket.py -d | --debug
  farmersmarket.py -v | --version
  farmersmarket.py -h | --help

Options:
  -i --item           Item.
  -q --quantity       Quantity.
  -p --price <price>  Price.
  -d --debug          Show debug messages.
  -h --help           Show this screen.
  -v --version        Show version.
"""

from docopt import docopt

print docopt(__doc__)

按预期工作:

 % farmersmarket.py buy --item eggs --quantity 100 --price 0.25
{'--debug': False,
 '--help': False,
 '--item': True,
 '--price': '0.25',
 '--quantity': True,
 '--version': False,
 '<item>': 'eggs',
 '<quantity>': ['100'],
 'buy': True}

编辑:

但实际上,你试图实现的是错误的。如果你看一下你将看到的解析参数:

 '--quantity': True,
 […]
 '<quantity>': ['100'],

表示您定义了一个布尔--quantity参数和一个位置quantity参数。两者都无关......结果如下:

buy --items eggs --quantity --price 0.25 100 2 

给出了结果:

 '--quantity': True,
 […]
 '<quantity>': ['100','2'],

这不是你想要的......所以让我们回到你想要的东西:你说你想要一个带有两个值的参数来定义一个min和一个可选的max。但我很遗憾地告诉您,在geptoptargparse而不是docopt中,这个确切的规则是不可能的。

解析完成后,解决方案将始终涉及一些逻辑,或者您需要更改解析参数的方式。所以我可以看到四个选项:

两个开关

Farmers market

Usage:
  farmersmarket.py buy -i <item> -m <min> [-M <max>] [-p <price>] [-dvh]
  farmersmarket.py -d | --debug
  farmersmarket.py -v | --version
  farmersmarket.py -h | --help

Options:
  -i --item <item>                  Item.
  -m --min <min>                    Minimal quantity.
  -M --max <min>                    Maximal quantity.
  -p --price <price>                Price.
  -d --debug                        Show debug messages.
  -h --help                         Show this screen.
  -v --version                      Show version.  

这里,最简单但我认为最好的解决方案是使用两个不同的选项来设置最大和最小边界。这是解析器处理{1,2}个参数的唯一方法,并且是应该实现它的方式。

使用单个参数

让你真正拥有列表参数的最接近的方法是使用语法实际“玩”:

Farmers market

Usage:
  farmersmarket.py buy -i <item> -q <quantity> [-p <price>] [-dvh]
  farmersmarket.py -d | --debug
  farmersmarket.py -v | --version
  farmersmarket.py -h | --help

Options:
  -i --item <item>                  Item.
  -q --quantity <quantity>          Quantity: min[,max]
  -p --price <price>                Price.
  -d --debug                        Show debug messages.
  -h --help                         Show this screen.
  -v --version                      Show version.  

然后你可以使用:

% farmersmarket.py buy --items eggs -q 100,2 --price 0.25

并通过if len(docopt(__doc__)['--quantity'].split(',')) == 2: qmin, qmax = docopt(__doc__)['--quantity'].split(',')获取最小值和最大值。

仅使用位置参数

最后,你的最后一个解决方案是仅使用位置参数:

Farmers market

Usage:
  farmersmarket.py buy <item> <min_qty> [<max_qty>] [-p <price>] [-dvh]
  farmersmarket.py -d | --debug
  farmersmarket.py -v | --version
  farmersmarket.py -h | --help

Options:
  <item>              Item.
  <min_qty>           Minimum quantity
  <max_qty>           Maximum quantity
  -p --price <price>  Price.
  -d --debug          Show debug messages.
  -h --help           Show this screen.
  -v --version        Show version.  

然后在你打电话时起作用:

% farmersmarket.py buy eggs 100 2 -p 0.25

选项列表

但是看起来你想要获得一个参数列表,并且使用命令行选项实现这一目的的唯一方法是重复选项-q 1 -q 2 -q 3…。要告诉docopt你想要什么,你需要在选项的参数后添加省略号:

Farmers market

Usage:
  farmersmarket.py buy -i <item> -q <quantity>... [-p <price>] [-dvh]
  farmersmarket.py -d | --debug
  farmersmarket.py -v | --version
  farmersmarket.py -h | --help

Options:
  -i --item <item>                  Item.
  -q --quantity <quantity>...       Quantity (-q min -q max)
  -p --price <price>                Price.
  -d --debug                        Show debug messages.
  -h --help                         Show this screen.
  -v --version                      Show version.  

然后你可以打电话:

% farmersmarket.py buy --items eggs -q 100 -q 2 --price 0.25 

但是,你必须检查len(docopt(__doc__)['--quantity']) < 2(因为解析器会强制你至少给出一个)。但是,你必须在描述中清楚地说明你的意思,并给出一两个例子。

最后,我建议你使用除选项列表之外的其他三个选项之一,因为它们可以让你更清楚地调用你的程序。