我想有以下规则
parser.add_argument('move', choices=['rock', 'paper', 'scissors'])
如果你传递了一个独特的角色子集,也可以工作(例如" k"或" oc"将被接受为"摇滚"但不是" ; r"因为它不是唯一的。)
我的需求是能够以最快的方式使用一个或多个参数运行脚本,以避免在子集足以让脚本理解选择时编写整个参数名称。
有没有办法获得这个结果仍然利用在帮助和错误处理中自动集成的方便选择列表?
答案 0 :(得分:5)
您可以定义list
的自定义子类,它支持您对in
运算符的定义为"包含(部分)元素恰好一次"像这样:
class argList(list):
def __contains__(self, other):
"Check if <other> is a substring of exactly one element of <self>"
num = 0
for item in self:
if other in item:
num += 1
if num > 1:
return False
return num==1
def find(self, other):
"Return the first element of <self> in which <other> can be found"
for item in self:
if other in item:
return item
然后你可以用它来构建你的参数列表:
>>> l = argList(["rock", "paper", "scissors"])
>>> "rock" in l
True
>>> "ck" in l
True
>>> "r" in l
False
>>> "q" in l
False
并使用它来构建解析器:
>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> l = argList(["rock", "paper", "scissors"])
>>> parser.add_argument("move", choices=l)
_StoreAction(option_strings=[], dest='move', nargs=None, const=None, default=Non
e, type=None, choices=['rock', 'paper', 'scissors'], help=None, metavar=None)
现在它正确处理参数(虽然错误信息仍然有点误导):
>>> parser.parse_args(["rock"])
Namespace(move='rock')
>>> parser.parse_args(["r"])
usage: [-h] {rock,paper,scissors}
: error: argument move: invalid choice: 'r' (choose from 'rock', 'paper', 'scissors')
请注意,保留输入的参数(当然)可能不完整:
>>> parser.parse_args(["ck"])
Namespace(move='ck')
所以你必须找出你选择的实际论点:
>>> args = parser.parse_args(["ck"])
>>> l.find(vars(args)["move"])
'rock'
我还没有进一步测试过 - 可能是重新定义`在参数列表中有意想不到的副作用,我想这样的程序行为是否违反了最少惊喜的原则是值得怀疑的 - 但是它是一个开始。
答案 1 :(得分:0)
蒂姆的解决方案非常有效,但如果您不想解决子类化list
的所有麻烦,您可以利用type
参数并定义您的自己的类型功能:
choices = ['rock','paper','scissors']
def substring(s):
options = [c for c in choices if s in c]
if len(options) == 1:
return options[0]
return s
parser = argparse.ArgumentParser()
parser.add_argument("move", choices = choices, type = substring)
当您传入move参数时,参数字符串将传递给您的子字符串函数。然后,如果参数字符串是您在choices
列表中定义的字符串中的一个字符串的子字符串,则它将返回该选项。否则,它将返回您的原始参数字符串,argparse可能会通过invalid choice
错误。