Python 使用argparse.ArgumentParser()获取分组结构
我想翻译如下内容:Python 使用argparse.ArgumentParser()获取分组结构,python,argparse,Python,Argparse,我想翻译如下内容: test.py --group 1 --opt1 foo1 --opt2 bar1 \ --group 2 --opt1 foo2 \ --group 3 --opt1 foo3 --opt2 bar3 --opt3 baz3 类似于字典的内容(如命名空间): 如果需要,输入可以是另一种格式 如果使用的不是(opt1、opt2、opt3),我想引发一个错误 我应该使用argparse.ArgumentParser() 你能帮忙吗?这是我能
test.py --group 1 --opt1 foo1 --opt2 bar1 \
--group 2 --opt1 foo2 \
--group 3 --opt1 foo3 --opt2 bar3 --opt3 baz3
类似于字典的内容(如命名空间):
- 如果需要,输入可以是另一种格式
- 如果使用的不是(opt1、opt2、opt3),我想引发一个错误
- 我应该使用argparse.ArgumentParser()
你能帮忙吗?这是我能想到的最好的,希望这就是你想要的 您需要以代码底部显示的形式提供参数,但您在文章中提到这是可以接受的 也就是说,使用
python3script.py--group1=2=3--opt1foo1=foo2=foo3--opt2bar1=None=bar3--opt3none=None=baz3
复制我的结果
import argparse, copy
parser = argparse.ArgumentParser()
parser.add_argument("--group", default='1')
parser.add_argument("--opt1", default='foo1')
parser.add_argument("--opt2", default='bar1')
parser.add_argument("--opt3", default='baz3')
args = parser.parse_args()
def splitter(arg):
return arg.split("=")
groups = splitter(args.group) if "=" in args.group else args.group
opt1 = splitter(args.opt1) if "=" in args.opt1 else args.opt1
opt2 = splitter(args.opt2) if "=" in args.opt2 else args.opt2
opt3 = splitter(args.opt3) if "=" in args.opt3 else args.opt3
# Dictionary with no values corresponding to just the keys in "group"
group_dict = dict.fromkeys(groups)
final_dict = copy.deepcopy(group_dict)
# Add dictionary inside each key - will remove blank keys later.
for key in group_dict:
group_dict[key] = dict.fromkeys(['opt1', 'opt2', 'opt3'])
# Now each group_dict has form
# {'3': {'opt2': None, 'opt3': None, 'opt1': None}, '2': {'opt2': None, 'opt3': None, 'opt1': None}, '1': {'opt2': None, 'opt3': None, 'opt1': None}}
# Must use group_dict['1']['opt3'] to access 1 -> opt3 -> value
for i, key in enumerate(groups):
group_dict[key]["opt1"] = opt1[i]
group_dict[key]["opt2"] = opt2[i]
group_dict[key]["opt3"] = opt3[i]
# Remove None elements - key is main dict - key2 & value are sub dict
final_dict[key] = {key2: value for key2, value in group_dict[key].items() if value != 'None'}
print(final_dict)
输出:
{'1': {'opt1': 'foo1', 'opt2': 'bar1'}, '2': {'opt1': 'foo2'}, '3': {'opt2': 'bar3', 'opt3': 'baz3', 'opt1': 'foo3'}}
摘要:
{'1': {'opt1': 'foo1', 'opt2': 'bar1'}, '2': {'opt1': 'foo2'}, '3': {'opt2': 'bar3', 'opt3': 'baz3', 'opt1': 'foo3'}}
argparse
,您可以改为使用--opt4
进行尝试这似乎是一个很酷的问题--
argparse
允许您以两种方式扩展其回调,一种是使用自定义类型的type=…
,另一种是使用自定义行为的action=…
。我认为type=
不可能出现上述问题,因此我采用了一种涉及action=
编写自定义操作的基本方法包括从argparse.action
继承和重写\uuuuuu调用\uuuuuuuuuuu
(以及可选的\uuuuu init\uuuuuu
)
这里是实现您想法的开始,您可能需要对其进行扩展/更改(例如,在action类中调用super()。\uuuu call\uuu(…)
,以处理基本行为(对于类型等)——我只使用了最简单的方法来满足您的问题
import argparse
导入pprint
类GroupAction(argparse.Action):
def uu调用(self、解析器、命名空间、值、选项u string=None):
组,=值
名称空间。\当前\组=组
groups=namespace.\uuuu dict\uuuu.setdefault('groups',{})
如果分组:
raise argparse.ArgumentError(self,f'已指定:{group}')
组[组]={}
类AppendToGroup(argparse.Action):
def uu调用(self、解析器、命名空间、值、选项u string=None):
值,=值
如果不是getattr(命名空间“\u当前\u组”,无):
raise argparse.ArgumentError(self,“组外!”)
namespace.groups[namespace.\u current\u group][self.dest]=值
parser=argparse.ArgumentParser()
parser.add_参数('--group',action=GroupAction)
add_参数('--opt1',action=AppendToGroup)
parser.add_参数('--opt2',action=AppendToGroup)
parser.add_参数('--opt3',action=AppendToGroup)
pprint.pprint(parser.parse_args().groups)
这里请注意,我使用名称空间来存储状态,因此不幸的是,最后您将得到一个额外的参数
\uuuuu dict\uuuuu.setdefault
有点狡猾,所以我会解释一下——这是一种略短的书写方式:
如果不是hasattr(名称空间,'groups'):
namespace.groups={}
groups=namespace.groups
我使用的基本策略是存储当前组,并在看到其他参数时附加到该组
以下是正在运行的示例:
$ python3.7 t.py --group 1 --opt1 a --opt2 b --opt3 c
{'1': {'opt1': 'a', 'opt2': 'b', 'opt3': 'c'}}
$ python3.7 t.py --group 1 --opt1 a --opt2 b --opt3 c --group 2
{'1': {'opt1': 'a', 'opt2': 'b', 'opt3': 'c'}, '2': {}}
$ python3.7 t.py --group 1 --opt1 a --opt2 b --opt3 c --group 2 --opt3 c
{'1': {'opt1': 'a', 'opt2': 'b', 'opt3': 'c'}, '2': {'opt3': 'c'}}
$ python3.7 t.py --group 1 --group 1
usage: t.py [-h] [--group GROUP] [--opt1 OPT1] [--opt2 OPT2] [--opt3 OPT3]
t.py: error: argument --group: already specified: 1
$ python3.7 t.py --opt1 a --group 1
usage: t.py [-h] [--group GROUP] [--opt1 OPT1] [--opt2 OPT2] [--opt3 OPT3]
t.py: error: argument --opt1: outside of group!
到目前为止,您做了些什么?查看此内容了解如何提问:我想也是使用外部配置…?每次调用只能有一个group
,或多个?如果有多个组,您可能希望使用命令行值以外的其他值,例如yaml
或json
文件。只需在命令行中提供文件名。@hpaulj是的,在我的回答中没有格式输入似乎是不可能的。如果需要的话,OP看起来很好。如果你要否决我的答案,请考虑让我知道为什么。我花了很多时间在这上面,并且希望知道我哪里出了错。l、 我喜欢使用额外的名称空间属性作为“state”变量,或者在操作之间进行通信。