问题:在不带任何参数的情况下调用脚本时,使用python argparse显示帮助消息
这可能很简单。假设我有一个使用argparse处理命令行参数/选项的程序。以下将打印“帮助”消息:
./myprogram -h
要么:
./myprogram --help
但是,如果我运行脚本时不带任何参数,则它不会执行任何操作。我要它做的是在不带参数的情况下显示用法消息。怎么做?
This might be a simple one. Assume I have a program that uses argparse to process command line arguments/options. The following will print the ‘help’ message:
./myprogram -h
or:
./myprogram --help
But, if I run the script without any arguments whatsoever, it doesn’t do anything. What I want it to do is to display the usage message when it is called with no arguments. How is that done?
回答 0
这个答案来自Google网上论坛的Steven Bethard 。我将其重新发布在这里,以方便没有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()
默认情况下会打印到标准输出。正如init_js建议的那样,用于parser.print_help(sys.stderr)
打印到stderr。
This answer comes from Steven Bethard on Google groups. I’m reposting it here to make it easier for people without a Google account to access.
You can override the default behavior of the error
method:
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()
Note that the above solution will print the help message whenever the error
method is triggered. For example, test.py --blah
will print the help message
too if --blah
isn’t a valid option.
If you want to print the help message only if no arguments are supplied on the
command line, then perhaps this is still the easiest way:
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()
Note that parser.print_help()
prints to stdout by default. As init_js suggests, use parser.print_help(sys.stderr)
to print to stderr.
回答 1
除了编写类,可以使用try / except代替
try:
options = parser.parse_args()
except:
parser.print_help()
sys.exit(0)
好处是工作流程更加清晰,您不需要存根类。不利的一面是第一行“用法”行被打印两次。
这将至少需要一个强制性参数。没有强制性参数,在命令行上提供零args是有效的。
Instead of writing a class, a try/except can be used instead
try:
options = parser.parse_args()
except:
parser.print_help()
sys.exit(0)
The upside is that the workflow is clearer and you don’t need a stub class. The downside is that the first ‘usage’ line is printed twice.
This will need at least one mandatory argument. With no mandatory arguments, providing zero args on the commandline is valid.
回答 2
使用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)
With argparse you could do:
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
如果必须为运行脚本指定参数,请对ArgumentParser 使用必需的参数,如下所示:-
parser.add_argument('--foo', required=True)
如果脚本不带任何参数运行,parse_args()将报告错误。
If you have arguments that must be specified for the script to run – use the required parameter for ArgumentParser as shown below:-
parser.add_argument('--foo', required=True)
parse_args() will report an error if the script is run without any arguments.
回答 4
如果您为(子)解析器关联了默认功能,如所述add_subparsers
,您可以简单地将其添加为默认操作:
parser = argparse.ArgumentParser()
parser.set_defaults(func=lambda x: parser.print_usage())
args = parser.parse_args()
args.func(args)
如果由于缺少位置参数而引发异常,请添加try-except。
If you associate default functions for (sub)parsers, as is mentioned under add_subparsers
, you can simply add it as the default action:
parser = argparse.ArgumentParser()
parser.set_defaults(func=lambda x: parser.print_usage())
args = parser.parse_args()
args.func(args)
Add the try-except if you raise exceptions due to missing positional arguments.
回答 5
最干净的解决方案是,如果在命令行中未提供默认参数,则手动传递默认参数:
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))
如果不带参数调用,这将打印出完整的帮助(不是简短用法)。
The cleanest solution will be to manually pass default argument if none were given on the command line:
parser.parse_args(args=None if sys.argv[1:] else ['--help'])
Complete example:
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))
This will print complete help (not short usage) if called w/o arguments.
回答 6
将我的版本扔到这里:
import argparse
parser = argparse.ArgumentParser()
args = parser.parse_args()
if not vars(args):
parser.print_help()
parser.exit(1)
您可能会注意到parser.exit
-我主要是这样做的,因为如果这是sys
文件中唯一的原因,它会保存导入行…
Throwing my version into the pile here:
import argparse
parser = argparse.ArgumentParser()
args = parser.parse_args()
if not vars(args):
parser.print_help()
parser.exit(1)
You may notice the parser.exit
– I mainly do it like that because it saves an import line if that was the only reason for sys
in the file…
回答 7
有一对可以完成这项工作的单行代码sys.argv[1:]
(这是一个非常常见的Python习惯用法,用于引用命令行参数,sys.argv[0]
即脚本的名称)。
第一个是不言自明的,干净的和pythonic的:
args = parser.parse_args(None if sys.argv[1:] else ['-h'])
第二个是一个小黑客。结合先前评估的事实,即空列表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])
There are a pair of one-liners with sys.argv[1:]
(a very common Python’s idiom to refer the command line arguments, being sys.argv[0]
the script’s name) that can do the job.
The first one is self-explanatory, clean and pythonic:
args = parser.parse_args(None if sys.argv[1:] else ['-h'])
The second one is a little hackier. Combining the previously evaluated fact that an empty list is False
with the True == 1
and False == 0
equivalences you get this:
args = parser.parse_args([None, ['-h']][not sys.argv[1:]])
Maybe too many brackets, but pretty clear if a previous argument selection was made.
_, *av = sys.argv
args = parser.parse_args([None, ['-h']][not av])
回答 8
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; 回声$?
用法:helloworld.py [-h] [--example]
示例基于argparser的python文件
可选参数:
-h,--help显示此帮助消息并退出
--example示例参数
我只是不知道出了什么问题,也许会丢失-示例条件?
128
$ python3〜/ helloworld.py-示例; 回声$?
0
parser.print_help()
parser.exit()
The parser.exit
method also accept a status
(returncode), and a message
value (include a trailing newline yourself!).
an opinionated example,
:)
#!/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
Example calls:
$ 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
回答 9
使用nargs设置位置参数,并检查位置args是否为空。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('file', nargs='?')
args = parser.parse_args()
if not args.file:
parser.print_help()
参考Python nargs
Set your positional arguments with nargs, and check if positional args are empty.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('file', nargs='?')
args = parser.parse_args()
if not args.file:
parser.print_help()
Reference Python nargs
回答 10
这是另一种实现方法,如果您需要一些灵活的方法,如果传递了特定的参数,则希望在显示帮助的地方显示帮助,则完全没有或超过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 ...
干杯!
Here is another way to do it, if you need something flexible where you want to display help if specific params are passed, none at all or more than 1 conflicting 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 ...
Cheers!
回答 11
如果您的命令是用户需要选择某些操作的命令,则使用具有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
If your command is something where a user needs to choose some action, then use a mutually exclusive group with required=True.
This is kind of an extension to the answer given by 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')
Output:
$ python3 a_test.py
usage: a_test.py [-h] (–batch pay_id | –list | –all)
a_test.py: error: one of the arguments –batch –list –all is required
This only give the basic help. And some of the other answers will give you the full help. But at least your users know they can do -h
回答 12
这不好(也因为拦截了所有错误),但是:
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
发送错误原因时,您将拦截它,看着它,然后……抛出。
This isn’t good (also, because intercepts all errors), but:
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(...)
...
Here is definition of the error
function of the ArgumentParser
class:
https://github.com/python/cpython/blob/276eb67c29d05a93fbc22eea5470282e73700d20/Lib/argparse.py#L2374
. As you see, following signature, it takes two arguments. However, functions outside the class nothing knows about first argument: self
, because, roughly speaking, this is parameter for the class. (I know, that you know…) Thereby, just pass own self
and message
in _error(...)
can’t (
def _error(self, message):
self.print_help()
sys.exit(-1)
def _args_get(args=sys.argv[1:]):
parser = argparser.ArgumentParser()
parser.error = _error
...
...
will output:
...
"AttributeError: 'str' object has no attribute 'print_help'"
). You can pass parser
(self
) in _error
function, by calling it:
def _error(self, message):
self.print_help()
sys.exit(-1)
def _args_get(args=sys.argv[1:]):
parser = argparser.ArgumentParser()
parser.error = _error(parser)
...
...
, but you don’t want exit the program, right now. Then return it:
def _error(parser):
def wrapper():
parser.print_help()
sys.exit(-1)
return wrapper
...
. Nonetheless, parser
doesn’t know, that it has been modified, thus when an error occurs, it will send cause of it (by the way, its localized translation). Well, then intercept it:
def _error(parser):
def wrapper(interceptor):
parser.print_help()
sys.exit(-1)
return wrapper
...
. Now, when error occurs and parser
will send cause of it, you’ll intercept it, look at this, and… throw out.