在没有任何参数的情况下调用脚本时,使用Python argparse显示帮助消息

假设我有一个程序,使用argparse来处理命令行参数/选项。下面将打印“帮助”信息:

./myprogram -h

或者:

./myprogram --help

但是,如果我不带任何参数运行脚本,它什么都不会做。我想要它做的是在不带参数地调用它时显示用法消息。怎么做呢?

198453 次浏览

这个答案来自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)

好处是工作流更加清晰,并且不需要存根类。缺点是第一个“usage”行打印了两次。

这至少需要一个强制参数。如果没有强制参数,在命令行上提供零参数是有效的。

在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的简要描述。如果fileNone,则假定为sys.stdout

把我的版本扔到这里:

import argparse


parser = argparse.ArgumentParser()
args = parser.parse_args()
if not vars(args):
parser.print_help()
parser.exit(1)

你可能会注意到parser.exit——我这样做主要是因为它保存了一个导入行,如果这是文件中sys的唯一原因……

如果脚本运行时必须指定参数,则使用ArgumentParser的要求参数,如下所示:-

parser.add_argument('--foo', required=True)

如果脚本在没有任何参数的情况下运行,Parse_args()将报告错误。

如果你关联(子)解析器的默认函数,如add_subparsers中提到的,你可以简单地将其添加为默认动作:

parser = argparse.ArgumentParser()
parser.set_defaults(func=lambda x: parser.print_usage())
args = parser.parse_args()
args.func(args)

如果由于缺少位置参数而引发异常,则添加try-except。

用nargs设置位置参数,检查位置参数是否为空。

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('file', nargs='?')
args = parser.parse_args()
if not args.file:
parser.print_help()

参考Python娜戈

最简洁的解决方案是手动传递默认参数,如果没有在命令行中给出:

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))

如果调用w/o参数,这将打印完整的帮助(而不是简短的用法)。

parser.print_help()
parser.exit()

parser.exit方法也接受一个status (returncode)和一个message值(包括一个尾随换行符自己!)

一个自以为是的例子, :) < / p >

#!/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; echo $?
usage: helloworld.py [-h] [--example]


Example argparser based python file


optional arguments:
-h, --help  show this help message and exit
--example   Example Argument


Something went wrong, --example condition was not set
64
$ python3 ~/helloworld.py --example; echo $?
0

这里有另一种方法来做,如果你需要一些灵活的东西,你想显示帮助,如果特定的参数被传递,没有或超过1个冲突的参数:

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 ...

干杯!

有一对带有sys.argv[1:](一种非常常见的Python习语,用于引用命令行参数,即sys.argv[0]脚本的名称)的一行程序可以完成这项工作。

第一个是不言自明的、干净的、python式的:

args = parser.parse_args(None if sys.argv[1:] else ['-h'])

第二个问题有点棘手。结合前面计算的事实,空列表是False,与True == 1False == 0等价,你得到:

args = parser.parse_args([None, ['-h']][not sys.argv[1:]])

也许括号太多了,但如果之前做了参数选择就很清楚了。

_, *av = sys.argv
args = parser.parse_args([None, ['-h']][not av])

如果你的命令是用户需要选择某个操作的命令,那么使用互斥组使用所需的= 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](——批pay_id |——列表|)< br > A_test.py:错误:参数之一——batch——list——all是必需的

这只是基本的帮助。其他的一些答案会给你充分的帮助。但至少你的用户知道他们可以做- h

这并不好(因为会拦截所有错误),但是:

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(...)
...

在这里ArgumentParser类的error函数的定义。

如您所见,下面的签名有两个参数。然而,类之外的函数对第一个参数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'"

你可以在_error函数中传递parser (self),通过调用它:

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将打印错误的原因,你将拦截它,查看它,然后…扔掉。

我喜欢让事情尽可能简单,这很有效:

#!/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)

这就是我如何开始我的所有工具,因为它总是好的包括一些例子

当调用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

这是一个很简单的答案。大多数时候使用argparse是为了检查是否设置了形参,以便调用函数来执行某些操作。

如果没有参数,则在最后输出else并打印帮助。简单而有效。

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)

这种方法比大多数其他方法要优雅得多。你可以通过包装parse_args()方法来更精确地控制行为,而不是重写error():

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)

这里的大多数答案都需要导入另一个模块,比如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函数来为用法语句提供帮助字符串。在调用ArgumentParser()时将add_help设置为False可以防止help语句在某些情况下打印两次。然而,为了在帮助消息中显示可选帮助参数,我必须为可选帮助参数创建一个参数,该参数在设置为False后模拟典型的帮助消息。该动作在help参数中被设置为store_true,以防止帮助消息在打印帮助消息时为参数填充类似HELP的值。