一个不需要位置参数的可选参数

4 投票
3 回答
1658 浏览
提问于 2025-04-16 22:33

我有个关于Python的argparse库的问题:有没有办法让一个可选参数不需要位置参数?

举个例子:

parser.add_argument('lat', help="latitude")
parser.add_argument('lon', help="longitude")
parser.add_argument('--method', help="calculation method (default: add)", default="add")
parser.add_argument('--list-methods', help="list available methods", action="store_true")

正常情况下,命令行的输入会是 test.py 47.249 -33.282 或者 test.py 47.249 -33.282 --method sub。但是当我用 test.py --list-methods 来列出所有可用的方法时,就会出现 error: to few arguments 的错误。这种情况下,我该怎么用argparse来实现这个可选参数(--list-methods),而不需要位置参数(纬度和经度)呢?

3 个回答

-1

你看到 error: to few arguments 这个错误,是因为程序需要你提供 latlon 这两个参数。

In [10]: parser.parse_args('--list-methods'.split())
ipython: error: too few arguments

但是

In [11]: parser.parse_args('--list-methods 10 20'.split())
Out[11]: Namespace(lat='10', list_methods=True, lon='20', method='add')

你应该把 latlon 这两个参数设置成可选的。

2

从Python 3.3开始,parse_args会检查它所看到的动作(seen_actions)是否满足所需的动作,并在需要时给出“以下参数是必需的...”的错误提示。之前,它会检查剩下的必填参数(positionals),如果不够就会抛出“参数太少”的错误信息。

所以在新版本中,这段代码应该能满足你的需求:

parser = argparse.ArgumentParser()
lat=parser.add_argument('lat', help="latitude")
lon=parser.add_argument('lon', help="longitude")
parser.add_argument('--method', help="calculation method (default: add)", default="add")

class MyAction(argparse._StoreTrueAction):
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, self.const)
        lat.required = False
        lon.required = False

parser.add_argument('--list-methods', help="list available methods", action=MyAction)

通常情况下,latlon是必填的参数,但如果执行了--list...这个动作,那么这些参数就不再是必需的,如果缺少它们也不会出现错误信息。


另外一种自定义argparse的方法是使用多个解析器。在这种情况下,你可以用一个解析器来检查--list-methods这个选项,然后根据得到的结果去调用另一个解析器来查找必填参数。

parser1 = argparse.ArgumentParser(add_help=False)
parser1.add_argument('--list-methods', help="list available methods", action='store_true')

parser2 = argparse.ArgumentParser()
parser2.add_argument('lat', help="latitude")
parser2.add_argument('lon', help="longitude")
parser2.add_argument('--method', help="calculation method (default: add)", default="add")
parser2.add_argument('--list-methods', help="list available methods", action='store_true')
def foo(argv):
    args,rest = parser1.parse_known_args(argv)
    if not args.list_methods:
        args = parser2.parse_args(argv)
    return args

parser2会响应帮助命令。parse_known_args会解析它能解析的内容,并把剩下的部分以列表的形式返回。parser2也可以被写成接受rest, args作为参数。

4
  • 为你的位置参数设置一个默认值,并且使用 nargs='?'
  • 在你的代码中手动检查一下,当你不在 list-methods 模式时,latitudelongitude 是否都已经设置好。

    parser = argparse.ArgumentParser()
    
    parser.add_argument('lat', help="latitude",default=None, nargs='?')
    parser.add_argument('lon', help="longitude",default=None, nargs='?')
    parser.add_argument('--method', help="calculation method (default: add)", default="add")
    parser.add_argument('--list-methods', help="list available methods", action="store_true")
    
    args = vars(parser.parse_args())
    
    if not args['list_methods'] and (args['lat'] == None or args['lon'] == None):
        print '%s: error: too few arguments' % sys.argv[0]
        exit(0)
    
    if args['list_methods']:
        print 'list methods here'
    else :
        print 'normal script execution'
    

这样会得到:

$ test.py --list-methods
这里列出方法

$ test.py 4
test.py: 错误:参数太少

test.py 4 5
正常执行脚本

撰写回答