假设我有一个argparse
用于处理命令行参数/选项的程序。以下将打印“帮助”消息:
./myprogram -h
或者:
./myprogram --help
但是,如果我在没有任何参数的情况下运行脚本,它不会做任何事情。我想要它做的是在不带参数的情况下调用它时显示使用消息。这是怎么做的?
这个答案来自Google groups 上的 Steven Bethard 。我在这里重新发布它是为了让没有谷歌帐户的人更容易访问。
您可以覆盖该error
方法的默认行为:
import argparse
import sys
class MyParser(argparse.ArgumentParser):
def error(self, message):
sys.stderr.write('error: %s\n' % message)
self.print_help()
sys.exit(2)
parser = MyParser()
parser.add_argument('foo', nargs='+')
args = parser.parse_args()
请注意,只要触发该error
方法,上述解决方案就会打印帮助消息。例如,如果不是有效选项,test.py --blah
也会打印帮助消息。--blah
如果您只想在命令行上未提供任何参数的情况下打印帮助消息,那么也许这仍然是最简单的方法:
import argparse
import sys
parser=argparse.ArgumentParser()
parser.add_argument('foo', nargs='+')
if len(sys.argv)==1:
parser.print_help(sys.stderr)
sys.exit(1)
args=parser.parse_args()
请注意,parser.print_help()
默认情况下打印到标准输出。正如init_js 建议的那样,用于parser.print_help(sys.stderr)
打印到 stderr。
代替编写类,可以使用 try/except
try:
options = parser.parse_args()
except:
parser.print_help()
sys.exit(0)
好处是工作流程更清晰,您不需要存根类。缺点是第一个“用法”行被打印了两次。
这将需要至少一个强制性参数。在没有强制参数的情况下,在命令行上提供零参数是有效的。
使用 argparse 你可以使用ArgumentParser.print_usage()
:
parser.argparse.ArgumentParser()
# parser.add_args here
# sys.argv includes a list of elements starting with the program
if len(sys.argv) < 2:
parser.print_usage()
sys.exit(1)
ArgumentParser.print_usage(file=None)
ArgumentParser
打印应如何在命令行上调用 的简要说明。如果file
是None
,sys.stdout
则假定。
如果您为(子)解析器关联默认函数,如下所述add_subparsers
,您可以简单地将其添加为默认操作:
parser = argparse.ArgumentParser()
parser.set_defaults(func=lambda x: parser.print_usage())
args = parser.parse_args()
args.func(args)
如果由于缺少位置参数而引发异常,请添加 try-except。
如果您有必须为脚本运行指定的参数 - 使用ArgumentParser所需的参数,如下所示: -
parser.add_argument('--foo', required=True)
如果脚本在没有任何参数的情况下运行,则 parse_args() 将报告错误。
如果在命令行上没有给出任何默认参数,最干净的解决方案将是手动传递默认参数:
parser.parse_args(args=None if sys.argv[1:] else ['--help'])
完整示例:
import argparse, sys
parser = argparse.ArgumentParser()
parser.add_argument('--host', default='localhost', help='Host to connect to')
# parse arguments
args = parser.parse_args(args=None if sys.argv[1:] else ['--help'])
# use your args
print("connecting to {}".format(args.host))
如果调用不带参数,这将打印完整的帮助(不是短用法)。
把我的版本扔在这里:
import argparse
parser = argparse.ArgumentParser()
args = parser.parse_args()
if not vars(args):
parser.print_help()
parser.exit(1)
您可能会注意到parser.exit
- 我主要是这样做的,因为如果这是文件中唯一的原因,它会保存一个导入行sys
......
有一对单行sys.argv[1:]
代码(一个非常常见的 Python 习惯用法来引用命令行参数,sys.argv[0]
即脚本的名称)可以完成这项工作。
第一个是不言自明的,干净的和pythonic:
args = parser.parse_args(None if sys.argv[1:] else ['-h'])
第二个有点hackier。结合先前评估的事实,即空列表False
与True == 1
和False == 0
等价,您会得到:
args = parser.parse_args([None, ['-h']][not sys.argv[1:]])
可能括号太多,但如果之前的参数选择是很清楚的。
_, *av = sys.argv
args = parser.parse_args([None, ['-h']][not av])
parser.print_help()
parser.exit()
该parser.exit
方法还接受一个status
(返回码)和一个message
值(包括自己的尾随换行符!)。
一个自以为是的例子,:)
#!/usr/bin/env python3
""" Example argparser based python file
"""
import argparse
ARGP = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawTextHelpFormatter,
)
ARGP.add_argument('--example', action='store_true', help='Example Argument')
def main(argp=None):
if argp is None:
argp = ARGP.parse_args() # pragma: no cover
if 'soemthing_went_wrong' and not argp.example:
ARGP.print_help()
ARGP.exit(status=64, message="\nSomething went wrong, --example condition was not set\n")
if __name__ == '__main__':
main() # pragma: no cover
示例调用:
$ python3 ~/helloworld.py; 回声$? 用法:helloworld.py [-h] [--example] 基于 argparser 的示例 python 文件 可选参数: -h, --help 显示此帮助信息并退出 --example 示例参数 出了点问题,--example 条件未设置 64 $ python3 ~/helloworld.py --example; 回声$? 0
因此,对于一个非常简单的答案。大多数情况下,使用 argparse 您正在检查是否设置了参数,以调用执行某些操作的函数。
如果没有参数,则在最后输出并打印帮助。简单而有效。
import argparse
import sys
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("--holidays", action='store_true')
group.add_argument("--people", action='store_true')
args=parser.parse_args()
if args.holidays:
get_holidays()
elif args.people:
get_people()
else:
parser.print_help(sys.stderr)
这里的大多数答案都需要另一个模块,例如sys
, 被导入或使用可选参数。我想找到一个只使用argparse
,使用必需参数的答案,并且如果可能的话,在不捕获异常的情况下工作。我最终得到以下结果:
import argparse
if __name__ == '__main__':
arg_parser = argparse.ArgumentParser(add_help=False)
arg_parser.add_argument('input_file', type=str, help='The path to the input file.')
arg_parser.add_argument('output_file', type=str, help='The path to the output file.')
arg_parser.add_argument('-h','--help', action='store_true', help='show this help message and exit')
arg_parser.usage = arg_parser.format_help()
args = arg_parser.parse_args()
主要思想是使用该format_help
函数为使用语句提供帮助字符串。在调用中设置add_help
为可防止帮助语句在某些情况下打印两次。但是,为了在帮助消息中显示可选帮助参数,我必须为模拟典型帮助消息的可选帮助参数创建一个参数。该操作在帮助参数中设置为,以防止帮助消息在打印帮助消息时填写参数的值。False
ArgumentParser()
False
store_true
HELP
我喜欢让事情尽可能简单,这很好用:
#!/usr/bin/env python3
Description = """Tool description"""
Epilog = """toolname.py -a aflag -b bflag with these combined it does blah"""
arg_parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=Description,
epilog=Epilog,
)
try:
if len(sys.argv) == 1:
arg_parser.print_help()
except Exception as e:
print(e)
这就是我开始所有工具的方式,因为包含一些示例总是很好
这是另一种方法,如果您需要一些灵活的东西,如果通过了特定参数,您想在其中显示帮助,则根本没有或超过 1 个冲突 arg:
import argparse
import sys
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--days', required=False, help="Check mapped inventory that is x days old", default=None)
parser.add_argument('-e', '--event', required=False, action="store", dest="event_id",
help="Check mapped inventory for a specific event", default=None)
parser.add_argument('-b', '--broker', required=False, action="store", dest="broker_id",
help="Check mapped inventory for a broker", default=None)
parser.add_argument('-k', '--keyword', required=False, action="store", dest="event_keyword",
help="Check mapped inventory for a specific event keyword", default=None)
parser.add_argument('-p', '--product', required=False, action="store", dest="product_id",
help="Check mapped inventory for a specific product", default=None)
parser.add_argument('-m', '--metadata', required=False, action="store", dest="metadata",
help="Check mapped inventory for specific metadata, good for debugging past tix", default=None)
parser.add_argument('-u', '--update', required=False, action="store_true", dest="make_updates",
help="Update the event for a product if there is a difference, default No", default=False)
args = parser.parse_args()
days = args.days
event_id = args.event_id
broker_id = args.broker_id
event_keyword = args.event_keyword
product_id = args.product_id
metadata = args.metadata
make_updates = args.make_updates
no_change_counter = 0
change_counter = 0
req_arg = bool(days) + bool(event_id) + bool(broker_id) + bool(product_id) + bool(event_keyword) + bool(metadata)
if not req_arg:
print("Need to specify days, broker id, event id, event keyword or past tickets full metadata")
parser.print_help()
sys.exit()
elif req_arg != 1:
print("More than one option specified. Need to specify only one required option")
parser.print_help()
sys.exit()
# Processing logic here ...
干杯!
当调用add_subparsers
方法保存第一个位置参数dest=
并在 argparse 初始化后检查值时,如下所示:
subparsers = parser.add_subparsers(dest='command')
只需检查这个变量:
if not args.command:
parser.print_help()
parser.exit(1) # If exit() - exit code will be zero (no error)
完整示例:
#!/usr/bin/env python
""" doc """
import argparse
import sys
parser = argparse.ArgumentParser(description=__doc__)
subparsers = parser.add_subparsers(dest='command',
help='List of commands')
list_parser = subparsers.add_parser('list',
help='List contents')
list_parser.add_argument('dir', action='store',
help='Directory to list')
create_parser = subparsers.add_parser('create',
help='Create a directory')
create_parser.add_argument('dirname', action='store',
help='New directory to create')
create_parser.add_argument('--read-only', default=False, action='store_true',
help='Set permissions to prevent writing to the directory')
args = parser.parse_args()
if not args.command:
parser.print_help()
parser.exit(1)
print(vars(args)) # For debug
这就是我想出的:
import sys
import argparse
HelpFlags = ('help', '--help', '-h', '/h', '?', '/?', )
class ArgParser (argparse.ArgumentParser):
def __init__(self, *args, **kws):
super().__init__(*args, **kws)
def parse_args(self, args=None, namespace=None):
if args is None:
args = sys.argv[1:]
if len(args) < 1 or (args[0].lower() in HelpFlags):
self.print_help(sys.stderr)
sys.exit()
return super().parse_args(args, namespace)
这不好(另外,因为拦截了所有错误),但是:
def _error(parser):
def wrapper(interceptor):
parser.print_help()
sys.exit(-1)
return wrapper
def _args_get(args=sys.argv[1:]):
parser = argparser.ArgumentParser()
parser.error = _error(parser)
parser.add_argument(...)
...
这error
是类的功能的定义ArgumentParser
。
如您所见,以下签名采用两个参数。但是,类外的函数对第一个参数一无所知self
,因为粗略地说,这个参数是针对类的。
def _error(self, message):
self.print_help()
sys.exit(-1)
def _args_get(args=sys.argv[1:]):
parser = argparser.ArgumentParser()
parser.error = _error
...
将输出:
"AttributeError: 'str' object has no attribute 'print_help'"
您可以在函数中传递parser
( self
),_error
方法是调用它:
def _error(self, message):
self.print_help()
sys.exit(-1)
def _args_get(args=sys.argv[1:]):
parser = argparser.ArgumentParser()
parser.error = _error(parser)
...
但是,如果您现在不想退出程序,请将其返回:
def _error(parser):
def wrapper():
parser.print_help()
sys.exit(-1)
return wrapper
尽管如此,parser
不知道它已被修改。因此,当发生错误时,它会打印错误的原因(顺便说一下,它是本地化翻译)。所以拦截它:
def _error(parser):
def wrapper(interceptor):
parser.print_help()
sys.exit(-1)
return wrapper
现在,当发生错误时,parser
将打印错误的原因,然后您将拦截它,查看它,然后......扔掉。
如果您的命令是用户需要选择某些操作的地方,那么请使用带有 required=True的互斥组。
这是对 pd321 给出的答案的一种扩展。
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--batch", action='store', type=int, metavar='pay_id')
group.add_argument("--list", action='store_true')
group.add_argument("--all", action='store_true', help='check all payments')
args=parser.parse_args()
if args.batch:
print('batch {}'.format(args.batch))
if args.list:
print('list')
if args.all:
print('all')
输出:
$ python3 a_test.py
用法:a_test.py [-h] (--batch pay_id | --list | --all)
a_test.py: 错误:参数之一 --batch --list --all 是必需的
这只提供基本的帮助。其他一些答案将为您提供全面的帮助。但至少你的用户知道他们可以做到-h
使用 nargs 设置位置参数,并检查位置参数是否为空。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('file', nargs='?')
args = parser.parse_args()
if not args.file:
parser.print_help()