关于python:一起使用Argparse和Json

Using Argparse and Json together

我是Python的初学者。

我想知道argparse和json是否可以一起使用。比如,我有变量p,q,r

我可以把它们添加到argparse中作为-

1
2
3
parser.add_argument('-p','--param1',help='x variable', required=True)
parser.add_argument('-q','--param2',help='y variable', required=True)
parser.add_argument('-r','--param3',help='z variable', required=True)

现在假设我想从JSON文件中读取相同的变量,是否可以这样做?所以我可以从命令行或JSON文件输入值。

JSON输入文件-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
   "testOwner":"my name",
   "tests": [
       "test1",
       "test2",
       "test3"
    ],

   "testParameters": {
       "test1": {
           "param1":"0",
           "param2":"20",
           "param3" :"True"
        },

       "test2": {
           "param1":"cc"
        }
    }  
}


来自parse_argsargs名称空间可以转换为字典:

1
argparse_dict = vars(args)

json值也在字典中,比如json_dict。您可以将所选值从一个字典复制到另一个字典,或进行整体比例更新:

1
argparse_dict.update(json_dict)

这样,json_dict值会重写argparse值。

如果要同时保留这两个参数,您要么需要具有不同的参数(键)名称,要么值必须是列表,您可以追加或扩展该列表。这需要做更多的工作,首先在argparse中使用正确的nargs值。

修订后的parser产生了一个测试输入:

1
2
3
4
5
6
In [292]: args=parser.parse_args('-p one -q two -r three'.split())
In [293]: args
Out[293]: Namespace(param1='one', param2='two', param3='three')
In [295]: args_dict = vars(args)    
In [296]: args_dict
Out[296]: {'param1': 'one', 'param2': 'two', 'param3': 'three'}

解析时的json字符串(json.loads)生成类似以下内容的字典:

1
2
3
4
5
6
In [317]: json_dict
Out[317]:
{'testOwner': 'my name',
 'testParameters': {'test1': {'param1': '0', 'param2': '20', 'param3': 'True'},
  'test2': {'param1': 'cc'}},
 'tests': ['test1', 'test2', 'test3']}

我通过将您的显示粘贴到我的IPython会话中生成了这个,但我认为JSON加载程序生成的是相同的东西。

argparse值可以添加为:

1
2
3
4
5
6
7
8
In [318]: json_dict['testParameters']['test3']=args_dict
In [319]: json_dict
Out[319]:
{'testOwner': 'my name',
 'testParameters': {'test1': {'param1': '0', 'param2': '20', 'param3': 'True'},
  'test2': {'param1': 'cc'},
  'test3': {'param1': 'one', 'param2': 'two', 'param3': 'three'}},
 'tests': ['test1', 'test2', 'test3']}

在这里,我把它添加为第三个test集,从tests列表中取了一个名字。json_dict['testParameters']['test2']=args_dict将取代test2的值。

向"test2"的未定义值添加args值的一种方法是:

1
2
3
4
5
6
7
8
9
10
In [320]: args_dict1=args_dict.copy()    
In [322]: args_dict1.update(json_dict['testParameters']['test2'])
In [324]: json_dict['testParameters']['test2']=args_dict1
In [325]: json_dict
Out[325]:
{'testOwner': 'my name',
 'testParameters': {'test1': {'param1': '0', 'param2': '20', 'param3': 'True'},
  'test2': {'param1': 'cc', 'param2': 'two', 'param3': 'three'},
  'test3': {'param1': 'one', 'param2': 'two', 'param3': 'three'}},
 'tests': ['test1', 'test2', 'test3']}

我使用这个版本的update来优先使用json字典中的"cc"值。


假设JSON文件包含以下形式的dict:

1
d = {"name": ["-x","--xvar"],"help":"Help message","required": True}

创建解析器之后,您可以像这样"解包"dict:

1
2
3
4
5
6
parser = argparse.ArgumentParser()
parser.add_argument(*(d.pop("name")), **d)
# Put the 'name' as name/flag and then unpack the rest of
# the dict as the rest of the arguments
parser.parse_args("--xvar 12".split())
>>> Namespace(xvar='12')

但是,这会迫使您维护dict键以适合方法add_arguments的参数名称。你也没有一个简单/直接的方法来使用更先进的行为,比如使用actiontypechoices参数。

此外,您还必须更改dict的格式,以包含要使用的各种参数。一种解决方案是将name/flag作为元组中dict的键,参数是dict:

1
2
3
4
5
6
d = {("-x","--xvar"): {"help":"Help message for x","required": True},
     ("-y","--yvar"): {"help":"Help message for y","required": True}}
for names, args in d.iteritems():
    parser.add_argument(*names, **args) # Use a similar unpacking 'magic' as the first example
parser.parse_args("-x 12 --yvar 42".split())
>>> Namespace(xvar='12', yvar='42')

编辑考虑到来自OP的注释,他似乎想要解析从JSON文件中获取的值。

1
2
3
4
5
6
d = {"-x":"12","-y":"42"}
args = []
for item in d.items():
    args.extend(item)
parser.parse_args(args)
>>> Namespace(xvar='12', yvar='42')

编辑2

查看argparse文档,这一段可能有些相关。