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

时间:2010-10-28 11:33:35

标签: python argparse

这可能很简单。假设我有一个使用argparse来处理命令行参数/选项的程序。以下将打印“帮助”消息:

./myprogram -h

或:

./myprogram --help

但是,如果我在没有任何参数的情况下运行脚本,它就不会做任何事情。我想要它做的是在没有参数的情况下调用它时显示用法消息。怎么做的?

16 个答案:

答案 0 :(得分:234)

这个答案来自Steven Bethard on Google groups。我在此处重新发布,以便让没有Google帐户的人更容易访问。

您可以覆盖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()默认情况下会打印到stdout。如init_js suggests,请使用parser.print_help(sys.stderr)打印到stderr。

答案 1 :(得分:43)

而不是写一个类,可以使用try / except代替

try:
    options = parser.parse_args()
except:
    parser.print_help()
    sys.exit(0)

好处是工作流程更清晰,您不需要存根类。缺点是第一次使用'线打印两次。

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

答案 2 :(得分:18)

使用argparse,你可以这样做:

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)

答案 3 :(得分:15)

如果您必须为要运行的脚本指定参数 - 请使用ArgumentParser的必需参数,如下所示: -

parser.add_argument('--foo', required=True)
如果脚本在没有任何参数的情况下运行,

parse_args()将报告错误。

答案 4 :(得分:11)

如果您为(子)解析器关联默认函数,如add_subparsers中所述,您只需将其添加为默认操作:

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

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

答案 5 :(得分:8)

把我的版本扔进这里:

import argparse

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

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

答案 6 :(得分:4)

最干净的解决方案是在命令行上没有给出默认参数:

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参数,这将打印完整的帮助(不是简短的用法)。

答案 7 :(得分:2)

可以使用一对带有sys.argv[1:]的单行代码(这是Python的一种常见用法,用于引用命令行参数,即脚本名sys.argv[0])。

第一个是不言自明的,干净的和pythonic的:

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

答案 8 :(得分:1)

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=128, message="\nI just don't know what went wrong, maybe missing --example condition?\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

I just don't know what went wrong, maybe missing --example condition?
128
$ python3 ~/helloworld.py --example; echo $?
0

答案 9 :(得分:1)

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

答案 10 :(得分:1)

所以对于一个非常简单的答案。大多数情况下,使用 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)

答案 11 :(得分:0)

使用nargs设置您的位置参数,并检查位置参数是否为空。

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

参考Python nargs

答案 12 :(得分:0)

这是另一种方法,如果你需要一些灵活的东西,你想要显示帮助,如果特定参数传递,没有一个或多于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 ...

干杯!

答案 13 :(得分:0)

如果您的命令是用户需要选择某些动作的内容,请使用互斥组 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](-批pay_id | --list | --all)
  a_test.py:错误:--batch --list --all参数之一是必需的

这仅提供基本帮助。其他一些答案将为您提供完整的帮助。但是至少您的用户知道他们可以 -h

答案 14 :(得分:0)

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

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函数的定义:

https://github.com/python/cpython/blob/276eb67c29d05a93fbc22eea5470282e73700d20/Lib/argparse.py#L2374

。如您所见,签名后需要两个参数。但是,类外的函数对第一个参数self一无所知,因为,粗略地说,这是该类的参数。 (我知道,您知道...)因此,仅在self中传递自己的message_error(...)不能(

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会发送错误原因时,您将拦截它,看着它,然后...抛出。

答案 15 :(得分:0)

我喜欢使事情尽可能简单,这很棒:

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

这是我开始使用所有工具的方式,因为它总是很好地包含一些示例