简体   繁体   English

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

[英]How can I avoid redundancy when I handle default arguments to modules that may also be parsed from the command line?

I'm trying to find a good way to avoid redundancy (that could possibly inject a risk for divergence) to my python module that can be executed from the command line. 我正在尝试寻找一种避免从命令行执行的python模块冗余的好方法(这可能会产生差异的风险)。

Consider a python module like this: 考虑这样的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)

So, someone using this module could either import it into their own code or call it from the command line. 因此,使用此模块的人可以将其导入自己的代码中,也可以从命令行中调用它。 I don't like that there is a redundancy in specifying the default value for the 'a' argument between the function definition and the command line parser. 我不喜欢在函数定义和命令行解析器之间为'a'参数指定默认值,这是多余的。 Aside from the aesthetic annoyance, I tend to fret that, in larger modules that might be edited via version control by many devs, one of the defaults could be changed but not the other. 除了美学上的烦恼之外,我倾向于担心,在许多开发人员可以通过版本控制来编辑的较大模块中,可以更改其中一个默认值,而不能更改其他默认值。

Is there a good way to eliminate the redundancy of specifying the default in two different places? 有没有一种好的方法来消除在两个不同位置指定默认值的冗余?

Alternatively, if you are using ArgumentDefaultsHelpFormatter to display the default values trough the usage message, you could do something like this: 另外,如果您使用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__)

On terminal: 在终端上:

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

You define it once and get it in three different places, without constants or poluting the function's body... 您只需定义一次即可在三个不同的位置获取它,而无需使用常量或污染函数的主体...


EDIT 编辑

I didn't know that much about recovering function metadata. 我对恢复功能元数据了解不多。 So, reading the docs was pretty helpful in order to answer this question. 因此, 阅读文档对于回答这个问题非常有帮助。 If you can, take a look at the inspect module of the Standard Library... 如果可以,请查看标准库的检查模块...

Here, another possibility, assigning the parameter defaults inside the function definition: 这是在函数定义中分配参数默认值的另一种可能性:

#!/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)

In Python 3, the "inspect" block would be a little bit more legible: 在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}

[...]

First, define funky to use None as default arguments instead: 首先,定义funky以使用None作为默认参数:

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

Then, let None be the default value for each command-line argument as well: 然后,也将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)

If the actual default values were to change, you only need to change them in one place (inside the body of funky ) rather than two places (in the definition of -a / -b and in the argument list to funky ). 如果要更改实际的默认值,则只需要在一个位置(在funky的主体内部)更改它们,而不是在两个位置(在-a / -b的定义以及在funky的参数列表中)进行更改。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从命令行运行 python 脚本时,PythonWin 也会运行。 我怎样才能避免这种情况? - When running a python script from command line, PythonWin also runs. How can I avoid this? 如何避免解释器检查函数的默认参数? - How can I avoid the interpreter checking the function default arguments? 可安装的distutils软件包:如何从也是同一软件包一部分的命令行脚本中导入软件包模块? - Installable distutils packages: How do I import package modules from command line scripts which are also part of the same package? 如何打包一个接受命令行参数并且还具有依赖关系的 Python 脚本? - How do I package a single python script which takes command line arguments and also has dependencies? 如何使用 vanila python 在命令行上获取 arguments? - How can I get the arguments on a command-line with vanila python? 如何使命令行参数对Flask路由可见? - How can I make command line arguments visible to Flask routes? 如何在Python中处理命令行参数? - How can I process command line arguments in Python? 如何在命令行中接受多个参数并正确处理它? - How can I accept multiple arguments in command line and process it correctly? 如何指定某些命令行参数在 Python 中是必需的? - How can I specify that some command line arguments are mandatory in Python? 如何使用命令行 arguments 参数化 pytest 夹具? - How can I parametrize a pytest fixture with command line arguments?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM