我可以检查值是由默认提供的还是由用户提供的?

Eri*_*ouf 7 python argparse

使用 时,是否有一种方法argparse可以判断字段是否具有值,因为用户指定了该值,还是因为未指定而获得了默认值?注意:我还想考虑用户明确指定默认值的情况。

我想用来argparse处理命令行参数,并且我想使用formatter_class=argparse.ArgumentDefaultsHelpFormatter显示未指定字段的默认值。此外,我想从配置文件中读取值。

如果用户在命令行上指定一个值,我想确保使用该值(即使该值与默认值匹配,但已明确说明)。如果用户没有指定值,但在配置文件中找到了一个值,我想使用它。如果用户没有在命令行上指定,并且配置文件中没有值,那么我想使用上面使用语句中显示的默认值。

所以,我可能会像这样设置解析

parser = parser = argparse.ArgumentParser( description="""Tool with many ways to get values""", formatter_class=argparse.ArgumentDefaultsHelpFormatter )
parser.add_argument( '-p', '--path', help="The path to a file to read", default="data.csv" )
parser.add_argument( '-c', '--conf', help="The config file to use", default="config.txt" )
Run Code Online (Sandbox Code Playgroud)

也许还有很多其他参数。

现在,我还想读取一个配置文件,其中可能包含一个值

data_path = data2.csv
Run Code Online (Sandbox Code Playgroud)

因此,如果用户-p在命令行上指定 a,我想读取该文件;如果他们不这样做并且我使用该配置文件,我想阅读data2.csv;如果我使用未定义且未data_path指定的配置文件-p,我想使用默认值data.csv。

对我来说,主要复杂的情况是,如果用户指定-p data.csv,那么它将具有默认值,但应优先于配置文件。

或其他类似的工具是否argparse有办法判断参数是通过默认设置还是由用户显式设置?

lar*_*sks 7

不要指定默认值,如果它会让事情变得复杂:

parser.add_argument('-p', '--path', 
                    help="The path to a file to read")
Run Code Online (Sandbox Code Playgroud)

然后在你的代码中:

if args.path:
    # user specify a value for path
    # using -p
    pass
elif cfg.path:
    # user provided a path in the configuration value
    args.path = cfg.path
else:
    # no value was specified, use some sort of default value
    args.path = DEFAULT_PATH
Run Code Online (Sandbox Code Playgroud)

或者,更紧凑:

args.path = next(val for val in 
                 [args.path, cfg.path, DEFAULT_PATH]
                 if val is not None)
Run Code Online (Sandbox Code Playgroud)

这cfg.path是假设None如果配置文件中没有指定路径的话。所以如果cfg实际上是一本字典,cfg.get('path')就会做正确的事情。

只是为了好玩,这里有一个可怕的想法,它可以区分使用默认值和显式指定与默认值相同的值之间的区别:

import argparse

class Default(object):
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return str(self.value)

DEFAULT_PATH = Default('/some/path')

def parse_args():
    p = argparse.ArgumentParser()
    p.add_argument('--path', '-p',
                   default=DEFAULT_PATH)
    return p.parse_args()

def main():
    args = parse_args()

    if args.path is DEFAULT_PATH:
        print 'USING DEFAULT'
    else:
        print 'USING EXPLICIT'

    print args.path

if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

请注意,我实际上并不认为这是一个好主意。

  • 我回避这一点并希望有另一种方法来说明的唯一原因是格式化使用声明。我可以手动将默认值包含在参数的“帮助”中,但确保它始终看起来像其他默认值可能会很痛苦。 (2认同)