Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用argparse的建议_Python_Argparse - Fatal编程技术网

Python 使用argparse的建议

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

我正在编写一个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来实现这一目的,但在正确地放置它时遇到了困难。现在,我正在做

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
树更多的代码行。我花了更长的时间编写。

by
grp1=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)