我想用 argparse 指定几个文件扩展名。
我试过下面的代码,但它不起作用。如何使用 argparse 指定多个文件扩展名?
parser.add_argument('file', action = 'store', type = argparse.FileType('r'), choices=["*.aaa", "*.bbb"])
编辑:我使用字符串类型而不是 FileType 找到了自己的解决方案:
def input_ok(string):
if not os.path.exists(string):
raise argparse.ArgumentTypeError("Filename %r doesn\'t exists in this directory." % string)
if string[-4:] != ".aaa" and string[-4:] != ".bbb":
raise argparse.ArgumentTypeError("%r is not a .aaa or a .bbb file." % string)
return string
...
parser.add_argument('input_path', action = 'store',
type = input_ok, #argparse.FileType('r'), #choices=["*.stl", "*.csv"])
最佳答案
问题的症结在于如何choices工作。 Argparse 首先构建传递参数的列表并进行类型转换,然后使用 in
运算符检查是否包含在选择中。这意味着它不会进行任何模式匹配(匹配 '*.aaa'
)但会检查字符串是否相等。相反,我们可以制作自己的容器以传递给选择。
不使用 argparse.Filetype
它看起来像这样。 Argparse 还需要容器具有 __iter__
来为帮助消息制作 Metavar 元组。
class Choices():
def __init__(self, *choices):
self.choices = choices
def __contains__(self, choice):
# True if choice ends with one of self.choices
return any(choice.endswith(c) for c in self.choices)
def __iter__(self):
return iter(self.choices)
parser.add_argument('file', action='store', choices=Choices('.aaa', '.bbb'))
您可以通过更改 __contains__
来扩展这个想法来做几乎任何事情以满足您的需要。例如,如果您还传递了 type=argparse.FileType('r')
,那么 argparse 将在检查包含之前转换为文件对象。
def __contains__(self, choice):
# choice is now a file object
return any(choice.name.endswith(c) for c in self.choices)
顺便说一句,这就是我讨厌 argparse 的原因。它过于复杂,并且试图做比它应该做的更多的事情。我认为不应在参数解析器中进行验证。使用 docopt并自己验证。
关于python - 使用 argparse 指定文件扩展名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20934424/