使用argparse时,应该在自定义类型或操作中进行验证和初始化吗?

Nic*_*ick 7 python argparse

Python 2.7的argparse为您提供了两个扩展点,您可以在其中控制命令行参数的解析方式:键入函数和操作类.

从内置类型和操作开始,最佳实践似乎是类型函数应该包含验证/初始化代码,并且操作应该关注将值存储到命名空间中.这种方法的问题是当你有类型检查代码有副作用.考虑这个简单的例子:

from argparse import ArgumentParser, FileType
argp = ArgumentParser()
argp.add_argument('-o', type=FileType('w'), default='myprog.out')
argp.parse_args(['-o', 'debug.out'])
Run Code Online (Sandbox Code Playgroud)

如果你运行它,你会发现python将在系统上打开两个文件,myprog.out并且debug.out.仅debug.out当用户不提供-o参数时才打开更有意义.

稍微调整一下,似乎argparse只会在传递的参数或str类型的默认参数上调用你的类型函数.如果你的类型检查器有副作用,这是很不幸的,因为即使传递了一个值,它也会在默认情况下被调用.因此,对于带有副作用的初始化,也许最好在动作中执行此操作.这样做的问题是,如果您提供默认值,则不会调用该操作!

请考虑以下代码:

from argparse import ArgumentParser, Action

def mytype(arg):
    print 'checking type for ' + repr(arg)
    return arg

class OutputFileAction(Action):
    def __call__(self, parser, namespace, values, option_string=None):
        print 'running action for ' + repr(values)
        try:
            outstream = open(values, 'w')
        except IOError as e:
            raise ArgumentError('error opening file ' + values)
        setattr(namespace, self.dest, outstream)

argp = ArgumentParser()
argp.add_argument('-o', type=mytype, action=OutputFileAction, default='myprog.out')
Run Code Online (Sandbox Code Playgroud)

现在尝试使用它:

>>> argp.parse_args([])
checking type for 'myprog.out'
Namespace(o='myprog.out')
>>> argp.parse_args(['-o', 'debug.out'])
checking type for 'myprog.out'
checking type for 'debug.out'
running action for 'debug.out'
Namespace(o=<open file 'debug.out', mode 'w' at 0x2b7fced07300>)
Run Code Online (Sandbox Code Playgroud)

谁下令这种行为?是否有一种理智的方式让默认值的行为与用户传入的完全相同?或者在提供值时不进行类型检查默认值?

mgi*_*son 2

据我所知,没有“明智”的方法可以做到这一点。当然,关闭type转换然后对Namespace返回的结果进行后处理是很简单的parse_args

args = argp.parse_args()
args.o = open(args.o,'w')
Run Code Online (Sandbox Code Playgroud)

但我想那不是你要找的。