// edit 1:略微更改了get_variable
-忘记添加传递给它的另一个参数(正在从内存写入它,对此感到抱歉)。
我对default
中的argparser
值有疑问。
某些值(如果不存在于命令行中)则使用os.env
从环境中获取,如果没有,则从DEFAULT_FOR_VARIABLE
获取:
def get_variable(name, DEFAULT_FOR_VARIABLE = ''):
if name in os.environ:
return os.environ[name]
print("no default value")
return DEFAULT_FOR_VARIABLE
这是main()
中的解析方式:
parser = argparse.ArgumentParser(description=MODULE_NAME)
parser.add_argument('--test_arg', default=get_variable(VAR_NAME, DEFAULT_FOR_TEST_ARG))
args = parser.parse_args()
print(args.test_arg)
无论是否传递参数,都将调用get_variable
函数,并且如果os.environ
中没有值,则会执行print
(让我知道缺少参数) ),即使传递了一个值:
λ python Parser_Test.py --test_arg test_arg
no default value
test_arg
未传递参数时,它按预期工作:
λ python Parser_Test.py
No default value
但是设置了DEFAULT_FOR_TEST_ARG
时:
λ python Parser_Test.py
No default value
DEFAULT_VALUE_FOR_TEST_ARG
检查每个已解析的参数也很困难,因为没有办法像argparse
那样对它们进行迭代-我要检查的用户很少。
有没有办法改变这种行为?还是在这种情况下应该使用非标准模块来解析参数?
答案 0 :(得分:1)
不确定我是否完全理解,但是您不能这样做吗?
def get_variable(name):
if name in os.environ:
return os.environ[name]
else:
print("no default value")
return 'empty'
或者:
parser = argparse.ArgumentParser(description=MODULE_NAME)
parser.add_argument('--test_arg',dest='test',nargs='?', default="empty")
args = parser.parse_args()
if args.test == "empty":
if name in os.environ:
newGlobalVar = os.environ["name"]
print("no default value")
else:
newGlobalVar = args.test
答案 1 :(得分:0)
get_variable(VAR_NAME)
方法时,解释器将评估 add_argument
。在python函数中,参数在传递给函数之前先经过评估。
argparse
会延迟评估默认值(如果它是字符串):
In [271]: p = argparse.ArgumentParser()
In [272]: p.add_argument('-f', type=int, default='12');
In [273]: p.parse_args('-f 23'.split())
Out[273]: Namespace(f=23)
In [274]: p.parse_args([])
Out[274]: Namespace(f=12)
此处,如果未提供-f
,则'12'
将传递给type
函数:
int('12')
或使用自定义type
:
In [275]: def mytype(astr):
...: print('eval',astr)
...: return int(astr)
In [276]: p.add_argument('-g', type=mytype, default='12');
In [277]: p.parse_args([])
eval 12
Out[277]: Namespace(f=12, g=12)
In [278]: p.parse_args(['-g','3'])
eval 3
Out[278]: Namespace(f=12, g=3)
但是在您的情况下,您想有条件地评估的代码可能无法通过type
函数处理。也就是说,您不会以与用户提供的字符串相同的方式评估默认值。
因此,解析后的测试可能最有意义。默认默认值为None
,可以很容易地对其进行测试:
if args.test is None:
args.test = 'the proper default'
用户无法提供任何会产生None
的字符串,因此这是安全的default
。
出于好奇,我写了一个type
,在os.environ
中查找了一个名字:
In [282]: def get_environ(name):
...: if name in os.environ:
...: return os.environ[name]
...: raise argparse.ArgumentTypeError('%s not in environ'%name)
In [283]: p.add_argument('-e', type=get_environ, default='DISPLAY');
没有参数,它将查找默认的os.environ['DISPLAY']
In [284]: p.parse_args([])
eval 12
Out[284]: Namespace(e=':0', f=12, g=12)
具有有效名称:
In [289]: p.parse_args(['-e','EDITOR'])
eval 12
Out[289]: Namespace(e='nano', f=12, g=12)
并在名称无效时引发错误:
In [290]: p.parse_args(['-e','FOO'])
usage: ipython3 [-h] [-f F] [-g G] [-e E]
ipython3: error: argument -e: FOO not in environ
An exception has occurred, use %tb to see the full traceback.
我知道这不是您的目标,但是它可以让您了解如果要延迟评估默认值的可能性。
答案 2 :(得分:0)
这是在python 3.6中使用lambda作为默认值的方法。我认为这是OP想要实现的目标。默认值不会立即得到评估。您可以轻松找到它们并在for循环中调用它们以解析值。我在t2参数中加入了默认字符串,以表明正常的默认设置在这种情况下仍然可以正常工作。
import argparse
import os
def get_value(var, dflt):
if var in os.environ:
return os.environ[var]
return dflt
parser = argparse.ArgumentParser(description=os.path.splitext(os.path.basename(__file__))[0])
parser.add_argument('--t1', default=lambda: get_value('t1_value', 't1 default'))
parser.add_argument('--t2', default='t2 default')
args = parser.parse_args()
print("Arguments have been parsed")
print(f"--t1: {args.t1}")
print(f"--t2: {args.t2}")
print("Lazily getting defaults")
for key in vars(args):
f = args.__dict__[key]
if callable(f):
print(f'Getting default value for {key}')
args.__dict__[key] = f()
print(f"--t1: {args.t1}")
print(f"--t2: {args.t2}")
结果:
Connected to pydev debugger (build 202.7660.27)
Arguments have been parsed
--t1: <function <lambda> at 0x000002425DD3FAE8>
--t2: t2 default
Lazily getting defaults
Getting default value for t1
--t1: t1_default
--t2: t2 default
Process finished with exit code 0
您可以使用专门的类来做类似的事情,但是我认为lambda更为简洁并且本质上是相同的。