首页 文章

Docopt:重复元素之后的选项作为重复元素进行交织

提问于
浏览
7

我在我的简单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的价格在 Value 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 回答

  • 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'],
    

    这不是你想要的......所以让's get back to what you want: you say you want an argument that takes two values to define a min and an optional max. But I'抱歉告诉你,这个确切的规则在 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 's what you want, you need to add an ellipsis after the option'的参数:

    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 (因为解析器会强制你至少给出一个) . 但是,你必须在描述中清楚地说明你的意思,并给出一两个例子 .

    最后,我建议您使用除选项列表之外的其他三个选项之一,因为它们使您更希望如何调用程序 .

相关问题