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

Can I check if a value was supplied by the default or by the user?

有没有办法在使用 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" )

也许还有很多其他参数。

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

data_path = data2.csv

所以如果用户在命令行指定了一个-p,我想读取那个文件;如果他们不这样做,而我使用该配置文件,我想阅读 data2.csv;如果我使用的配置文件没有定义 data_path 并且他们没有指定 -p,我想使用默认的 data.csv.

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

argparse 或其他类似工具是否有办法判断参数是通过下降到默认设置还是由用户明确设置?

如果它只会使事情复杂化,请不要指定默认值:

parser.add_argument('-p', '--path', 
                    help="The path to a file to read")

稍后在您的代码中:

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

或者,更简洁:

args.path = next(val for val in 
                 [args.path, cfg.path, DEFAULT_PATH]
                 if val is not None)

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

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

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()

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