Python 使用argparse的建议
我正在编写一个python命令行客户端程序来与api接口。用户使用客户端程序运行以下命令,客户端程序对api进行以下示例调用 python run.py--car-->调用方法get_all(车辆类型),该方法请求-->/car/all--<返回所有车辆的列表 python run.py--van-->/van/all-->返回所有van的列表 /car/id/123-->-->调用方法get_by_id(vehicle_type,id),该方法请求-->返回id为123的汽车列表 其他所有人都是如此 /汽车/颜色/红色红色汽车退货清单 /轿厢/型号\u no/31x带型号\u no 31x的返回轿厢 /van/id/312返回id为321的van列表 我正在使用arg parse来实现这一目的,但在正确地放置它时遇到了困难。现在,我正在做Python 使用argparse的建议,python,argparse,Python,Argparse,我正在编写一个python命令行客户端程序来与api接口。用户使用客户端程序运行以下命令,客户端程序对api进行以下示例调用 python run.py--car-->调用方法get_all(车辆类型),该方法请求-->/car/all--/van/all-->返回所有van的列表 /car/id/123-->-->调用方法get_by_id(vehicle_type,id),该方法请求-->返回id为123的汽车列表 其他所有人都是如此 /汽车/颜色/红色红色汽车退货清单 /轿厢/型号\u n
parser = argparse.ArgumentParser()
grp1 = parser.add_mutually_exclusive_group(required=True)
grp2 = parser.add_mutually_exclusive_group()
grp1.add_argument('--car', action='store_const', const='car')
grp1.add_argument('--van', action='store_const', const='van')
grp2.add_argument('--id', help='get by id')
grp2.add_argument('--model_no', help='get by model number')
grp2.add_argument('--color', help='get by color')
arg_dict = {k:v for k, v in vars(args).items() if v}
当我为命令运行此代码时
python run.py--car--ID123
我明白了
{'car':'car','id':'123'}
我循环使用这个dict,并使用getattr通过键名“get_by_{name}”调用函数。format(name=key)。
但是,我的代码看起来不太好,因为我必须检查长度是否为1,然后调用get all函数并检查车辆类型。是否有更好的方法正确使用argparse使代码更紧凑。我发现,在使用互斥组时,我经常使用,因此有一个变量具有动态值:
import argparse
parser = argparse.ArgumentParser()
grp1 = parser.add_mutually_exclusive_group(required=True)
grp2 = parser.add_mutually_exclusive_group()
group_1_options = {"action":"store_const",'dest':"vehicle"}
grp1.add_argument('--car', const="car", **group_1_options)
grp1.add_argument('--van', const='van', **group_1_options)
然后,对于第二组,您可以使用type
在指定选项时应用更改,以便保存对指定选项文本的引用:
parser.set_defaults(request=("get_all",None))
request_args = {"id":'get by id',
"model_no":"get by model number",
"color":"get by color"}
grp2 = parser.add_mutually_exclusive_group()
for arg_name, help_text in request_args.items():
grp2.add_argument("--"+arg_name, help=help_text, dest="request",
type=(lambda x, arg_text=arg_name:(arg_text,x)))
然后可以检索请求,如下所示:
def test(argline):
namespace = parser.parse_args(argline.split())
kind,value = namespace.request
print(namespace.vehicle, kind, value)
然后保证您只需处理车辆
和请求
选项:
>>> test("--van")
van get_all None
>>> test("--car --id 123")
car id 123
>>> test("--model_no 55 --van")
van model_no 55
>>> test("--car --id") #invalid because there is no request value
usage: test.py [-h] (--car | --van)
[--color REQUEST | --id REQUEST | --model_no REQUEST]
test.py: error: argument --id: expected one argument
做你想做的事情(我认为)的一个相对直接的方法是: 您可以使用
default=argparse.SUPPRESS
将id
保留在args
之外(就像您使用arg\u dict={k:v代表k,v在vars(args)中)。items()如果v}
,但是测试起来更容易
if args.id:
...
或
如果确实想从args
值生成函数名,可以执行字典查找(locals()
或自定义字典)。内部argparse
通过解析器使用注册表
字典。注册
fn = locals().get('get_by_%s'%'id')
fn(args.vehicle_type, args.id)
argparse
文档显示了如何使用parser.set\u defaults
将args
属性定义为函数。但该特定用法仅适用于子parser
您可以使用const
设置函数,例如
getby_group.add_argument('--id',dest='fn',action='store_const', const=get_by_id)
然后
将运行get\u by\u id
函数
<删除了使用此存储常数的版本。
在接受值时遇到问题;设置编辑历史记录以获取详细信息>
===================
这里有一个自定义操作方法来定义fn
属性和值
class GetAction(argparse._StoreAction):
# barest customization
def __init__(self, *args, **kwargs):
fn=kwargs.pop('fn')
super(GetAction, self).__init__(*args, **kwargs)
self.fn = fn
def __call__(self, parser, namespace, values, option_string=None):
super(GetAction, self).__call__(parser, namespace, values, option_string=None)
setattr(namespace, 'fn', self.fn)
parser.set_defaults(fn=get_all) # default action
getby_group.add_argument('--id', dest='value', action=GetAction, fn=get_by_id)
getby_group.add_argument('--color',dest='value', action=GetAction, fn=get_by_color)
getby_group.add_argument('--model',dest='value', action=GetAction, fn=get_by_model)
args = parser.parse_args()
args.fn(args.vehicle_type, args.value)
但是-请注意,类定义需要比
if-else
树更多的代码行。我花了更长的时间编写。bygrp1=parser.add(…)
您的意思可能是grp1.add_参数(…)
?谢谢你的更正。非常感谢。这使它更简单。但是,颜色需要参数。这一个似乎返回请求类型,但我也需要请求参数,例如可以是红色。对……这肯定会简化第一组,但我不确定如何简化第二组。等等,是不是他甚至知道你在寻找什么,或者我是在完全错误的方向上吗?我只是在寻找一种简洁的方法来做这件事。我认为你的回答肯定会有帮助。如果你有更多的建议(比如你处理这个问题的方式),我会很乐意倾听。有可能得到类似名称空间的参数颜色、id、型号吗(车辆='van',请求={'color':'red'})第一种方法绝对是最简单的,但是OP特别寻找更紧凑的东西,而您的最后一个示例失败了,因为它使value
成为必需的,并且与前面指定的选项完全无关。使用自定义操作类,您可以设置fn
属性并获取一个值。这只会使语法分析器定义的复杂性。有时避免一个简单的if-else
树是不值得的。哦,你建议创建一个自定义操作类,这并不清楚。我已经制定了一个自定义操作,它将定义fn
属性并获取一个值。老实说,我感觉自己像是一个互斥组中的功能“所选选项的名称存储在此变量中,该选项的值存储在此变量中“这将是一个非常有用的功能,无论如何,我认为自定义操作更容易扩展,因为添加带有if/else
的选项需要在最基本的情况下添加三行,但始终与自定义操作一起添加一行。
fn = locals().get('get_by_%s'%'id')
fn(args.vehicle_type, args.id)
getby_group.add_argument('--id',dest='fn',action='store_const', const=get_by_id)
args.fn(...)
class GetAction(argparse._StoreAction):
# barest customization
def __init__(self, *args, **kwargs):
fn=kwargs.pop('fn')
super(GetAction, self).__init__(*args, **kwargs)
self.fn = fn
def __call__(self, parser, namespace, values, option_string=None):
super(GetAction, self).__call__(parser, namespace, values, option_string=None)
setattr(namespace, 'fn', self.fn)
parser.set_defaults(fn=get_all) # default action
getby_group.add_argument('--id', dest='value', action=GetAction, fn=get_by_id)
getby_group.add_argument('--color',dest='value', action=GetAction, fn=get_by_color)
getby_group.add_argument('--model',dest='value', action=GetAction, fn=get_by_model)
args = parser.parse_args()
args.fn(args.vehicle_type, args.value)