[英]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... 您只需定义一次即可在三个不同的位置获取它,而无需使用常量或污染函数的主体...
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.