在Python中从Namespace获取必需选项

时间:2015-02-18 09:08:05

标签: python argparse

我创建了一个这样的ArgumentParser:

argpr = ArgumentParser()
argpr.add_argument('--long-c', '-c', required=True, dest='long_c') 

如果我存在json配置文件,我将配置添加到命名空间:

cfg = argparse.Namespace()
if json_dict is not None:
    cfg.long_c = json['long-c']
print vars(cfg)

然后我使用Namespace作为参数解析器的参数,如下所示:

use_cfg = argpr.parse_args(namespace=cfg)

我可以看到我在我的Namespace对象中得到一个值,因此我希望ArgumentParser.parse_args在我的Namespace对象中找到long_c但是得到:

argument --long-c/-c is required

我做错了吗?这是一个错误还是预期的行为?有关如何使这项工作的任何建议值得欢迎=)

提前谢谢

编辑: - 修正了拼写错误。 - 将名称空间更改为Namespace对象。 - 澄清了我对Namespace对象的使用和我的期望。

3 个答案:

答案 0 :(得分:3)

创建和使用命名空间的方式(在进行更正后)没有任何问题,但正如AndréLaszlo所说,你的期望是错误的:

  

...我希望ArgumentParser.parse_args在我的网站中找到long_c   命名空间对象,但我得到:

argument --long-c/-c is required

很容易证明argparse不能那样工作:

import argparse as ap

argpr = ap.ArgumentParser()
argpr.add_argument('--long-c', '-c', required=True, dest='long_c')

cfg = ap.Namespace()  
print(cfg)

name_space = argpr.parse_args(namespace=cfg)
print(name_space.long_c)
print(name_space)  #name_space and cfg are different names for the same object 

--output:--
$ python3.4 1.py -c 4
Namespace()
4
Namespace(long_c='4')

(请注意,如果您希望存储的值为int,则可以将type=int添加到a​​dd_argument())

现在cfg名称空间已经具有long_c的值:

import argparse as ap

argpr = ap.ArgumentParser()
json_dict = {'long-c': 5}

cfg = ap.Namespace()

if json_dict:
   cfg.long_c = json_dict['long-c']

print(cfg)

argpr.add_argument('--long-c', '-c', required=True, dest='long_c')
name_space = argpr.parse_args(namespace=cfg)
print(name_space.long_c)

print(name_space)  #name_space and cfg are different names for the same object 

--output:--
$ python3.4 1.py -c 4
Namespace(long_c=5)
4
Namespace(long_c='4')

但是...

$ python3.4 1.py
Namespace(long_c=5)
usage: 1.py [-h] --long-c LONG_C
1.py: error: the following arguments are required: --long-c/-c

要获得所需的行为,如果json_dict已经有了一个值,你需要使-c选项可选,如下所示:

cfg = ap.Namespace()
required = True

if json_dict:
    val = json_dict.get('long-c', False) 

    if val:
        cfg.long_c = val
        required = False

print(cfg)

argpr.add_argument('--long-c', '-c', required=required, dest='long_c')

答案 1 :(得分:1)

Namespace不是用于传递参数,而是用于存储结果。您需要在args参数中传递配置。我想这就是你追求的目标:

cfg = []
if json_dict is not None:
    cfg.extend(('-c', json['long-c']))
use_cfg = argpr.parse_args(cfg)

我知道你要做什么,但我不认为argparse会按照你想要的方式检查命名空间中的所需参数。通常,您不需要提供namespace参数,但如果您希望将已解析的参数分配给现有对象,则可能会很好。

另外,如果你想要显式创建Namespace,请务必实例化它:

# use this:
argparse.Namespace()
# not this:
argparse.Namespace

否则,您最终会将属性分配给Namespace类本身。

另请阅读required上的说明:

  

注意:由于用户,所需的选项通常被视为不良格式   期望选项是可选的,因此应该避免它们   可能的。

答案 2 :(得分:1)

我将ArgumentParser子类化为您想要它做的事情。

import json
from argparse import ArgumentParser

class ConfigurableArgumentParser(ArgumentParser):

    def __init__(self, config_file, *args, **kwargs):
        self.config = json.load(config_file)
        super(ConfigurableArgumentParser, self).__init__(*args, **kwargs)

    def add_argument(self, *args, **kwargs):
        store_action = super(ConfigurableArgumentParser, self).add_argument(
            *args, **kwargs)
        dest = store_action.dest
        if dest in self.config:
            store_action.default = self.config[dest]
            store_action.required = False
        return store_action

此参数解析器采用额外的构造函数参数config_file,该参数应该是指向JSON配置文件的文件对象。 add_argument方法被修改为使用配置文件中的默认值(如果存在),在这种情况下required也将设置为False

用法:

if __name__ == '__main__':
    from StringIO import StringIO

    # config_file = open('my_config.json')
    config_file = StringIO('{"long_c": "1"}')

    parser = ConfigurableArgumentParser(config_file)
    parser.add_argument('--long-c', '-c',
                        required=True, dest='long_c', type=int)
    namespace = parser.parse_args()
    print namespace
    # Output:
    # Namespace(long_c=1)

请注意,类型仍按照应有的方式处理,JSON字符串会自动转换为int