当我处理可能也从命令行解析的模块的默认参数时,如何避免冗余?

时间:2015-01-26 21:00:17

标签: python argparse

我试图找到一种很好的方法来避免冗余(可能会产生分歧的风险)到我的python模块,可以从命令行执行。

考虑一个像这样的python模块:

#!/usr/bin/env python2.7
from argparse import ArgumentParser

DEFAULT_A_ARG='alpha'

def funky(a=DEFAULT_A_ARG, b=False):
    pass

if __name__ == '__main__':
    parser = ArgumentParser()
    parser.add_argument('-a', default=DEFAULT_A_ARG)
    parser.add_argument('-b', action='store_true', default=False)
    args = parser.parse_args()
    funky(a=args.a, b=args.b)

因此,使用此模块的人可以将其导入自己的代码或从命令行调用它。我不希望在指定' a'的默认值时存在冗余。函数定义和命令行解析器之间的参数。除了审美烦恼之外,我倾向于担心,在可能通过许多开发人员的版本控制进行编辑的较大模块中,其中一个默认值可以更改,但不能更改另一个。

有没有一种好方法可以消除在两个不同位置指定默认值的冗余?

2 个答案:

答案 0 :(得分:1)

或者,如果您使用ArgumentDefaultsHelpFormatter通过使用消息显示默认值,则可以执行以下操作:

#!/usr/bin/env python2.7
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter

parser = ArgumentParser(prog='my_program',
                        formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('-a', default='alpha', help='your favorite greek letter')
parser.add_argument('-b', action='store_true', help='print numbers in binary format')

def funky(a=parser.get_default('a'), b=parser.get_default('b')):
    pass

if __name__ == '__main__':
    args = parser.parse_args()
    funky(**args.__dict__)

在终端上:

$ my_program.py --help
usage: my_program [-h] [-a A] [-b]

optional arguments:
  -h, --help  show this help message and exit
  -a A        your favorite Greek letter (default: alpha)
  -b          print number in binary format (default: False)

你定义它一次并在三个​​不同的地方得到它,没有常数或者调用函数体......


修改

我对恢复功能元数据知之甚少。所以,阅读文档对于回答这个问题非常有帮助。如果可以,请查看标准库的inspect模块...

这是另一种可能性,在函数定义中指定参数默认值:

#!/usr/bin/env python2.7
from argparse import ArgumentParser

def funky(x, a='alpha', b=False):
    pass

if __name__ == '__main__':
    import argparse
    import inspect

    funky_spec = inspect.getargspec(funky)
    defaults = funky_spec.defaults
    defaults = dict(zip(funky_spec.args[-len(defaults):], defaults))
    # effect: ['x', 'a', 'b'] + ('alpha', False) -> {'a': 'alpha', 'b': False}

    parser = argparse.ArgumentParser()
    parser.add_argument('x', help='input number')
    parser.add_argument('-a', default=defaults['a'])
    parser.add_argument('-b', action='store_true', default=defaults['b'])
    args = parser.parse_args()

    funky(x=args.x, a=args.a, b=args.b)

在Python 3中,"检查"块会更清晰:

[...]

    funky_params = inspect.signature(funky).parameters.values()
    defaults = {p.name: p.default for p in funky_params if p.default is not p.empty}

[...]

答案 1 :(得分:0)

首先,将funky定义为使用None作为默认参数:

def funky(a=None, b=None):
    if a is None:
        a = DEFAULT_A_ARG
    if b is None:
        b = False

然后,让None成为每个命令行参数的默认值:

if __name__ == '__main__':
    parser = ArgumentParser()
    # You probably don't have to specify a default of None explicitly
    parser.add_argument('-a', default=None)
    parser.add_argument('-b', action='store_true', default=None)
    args = parser.parse_args()
    funky(a=args.a, b=args.b)

如果要更改实际默认值,您只需要在一个位置(funky的主体内)而不是两个位置(在-a / {{1的定义中)更改它们并且在参数列表中-b)。