在解析Python命令行参数方面,哪种方法或库是最简单、简洁和灵活的?
在解析Python命令行参数方面,哪种方法或库是最简单、简洁和灵活的?
argparse
是正确的选择。以下是如何使用它的简要概述:
1)初始化
import argparse
# Instantiate the parser
parser = argparse.ArgumentParser(description='Optional app description')
2) 添加参数
# Required positional argument
parser.add_argument('pos_arg', type=int,
help='A required integer positional argument')
# Optional positional argument
parser.add_argument('opt_pos_arg', type=int, nargs='?',
help='An optional integer positional argument')
# Optional argument
parser.add_argument('--opt_arg', type=int,
help='An optional integer argument')
# Switch
parser.add_argument('--switch', action='store_true',
help='A boolean switch')
3) 解析
args = parser.parse_args()
4) 访问
print("Argument values:")
print(args.pos_arg)
print(args.opt_pos_arg)
print(args.opt_arg)
print(args.switch)
5) 检查数值
if args.pos_arg > 10:
parser.error("pos_arg cannot be larger than 10")
正确使用:
$ ./app 1 2 --opt_arg 3 --switch
Argument values:
1
2
3
True
错误的参数:
$ ./app foo 2 --opt_arg 3 --switch
usage: convert [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
app: error: argument pos_arg: invalid int value: 'foo'
$ ./app 11 2 --opt_arg 3
Argument values:
11
2
3
False
usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
convert: error: pos_arg cannot be larger than 10
完整帮助:
$ ./app -h
usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
Optional app description
positional arguments:
pos_arg A required integer positional argument
opt_pos_arg An optional integer positional argument
optional arguments:
-h, --help show this help message and exit
--opt_arg OPT_ARG An optional integer argument
--switch A boolean switch
optparse
,适用于较早版本的Python。对于Python 2.7及以上版本,argparse
替代了optparse
。有关更多信息,请参见此答案。
正如其他人所指出的,与getopt相比,你最好选择optparse。 getopt基本上是标准getopt(3)C库函数的一对一映射,并且不太容易使用。
虽然optparse略微冗长,但结构更好,以后扩展也更简单。
以下是向解析器添加选项的典型行:
parser.add_option('-q', '--query',
action="store", dest="query",
help="query string", default="spam")
它几乎是自解释的,处理时,它将接受-q或--query作为选项,将参数存储在称为query的属性中,并且如果您没有指定它,则具有默认值。此外,它也是自我记录的,因为您在选项旁边声明了帮助参数(当使用-h / --help运行时将使用该参数)。
通常您会使用以下方式解析参数:
options, args = parser.parse_args()
默认情况下,这将解析传递给脚本的标准参数(sys.argv[1:])。
options.query 将被设置为您传递给脚本的值。
只需执行以下操作即可创建解析器
parser = optparse.OptionParser()
以下是您所需的所有基础知识。下面是一个完整的 Python 脚本,显示了这一点:
import optparse
parser = optparse.OptionParser()
parser.add_option('-q', '--query',
action="store", dest="query",
help="query string", default="spam")
options, args = parser.parse_args()
print 'Query string:', options.query
展示Python基础知识的5行代码。
将其保存在sample.py文件中,使用以下命令运行一次:
python sample.py
并且一次使用
python sample.py --query myquery
自2012年以来,有一个非常简单、强大和真正“酷”的参数解析模块叫做docopt。以下示例摘自其文档:
"""Naval Fate.
Usage:
naval_fate.py ship new <name>...
naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
naval_fate.py ship shoot <x> <y>
naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
naval_fate.py (-h | --help)
naval_fate.py --version
Options:
-h --help Show this screen.
--version Show version.
--speed=<kn> Speed in knots [default: 10].
--moored Moored (anchored) mine.
--drifting Drifting mine.
"""
from docopt import docopt
if __name__ == '__main__':
arguments = docopt(__doc__, version='Naval Fate 2.0')
print(arguments)
就是这样:只需两行代码再加上必不可少的文档字符串,您就可以解析参数并在参数对象中使用。
自2017年以来,还有另一个很酷的模块称为python-fire。它可以为您的代码生成一个CLI界面,而您无需进行任何参数解析。这里是文档中的一个简单示例(此小程序将函数double
公开到命令行):
import fire
class Calculator(object):
def double(self, number):
return 2 * number
if __name__ == '__main__':
fire.Fire(Calculator)
你可以从命令行运行以下命令:
> calculator.py double 10
20
> calculator.py double --number=15
30
我更喜欢 Click。它抽象了管理选项的过程,并允许“用尽可能少的代码以可组合的方式创建美丽的命令行界面”。
以下是使用示例:
import click
@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
help='The person to greet.')
def hello(count, name):
"""Simple program that greets NAME for a total of COUNT times."""
for x in range(count):
click.echo('Hello %s!' % name)
if __name__ == '__main__':
hello()
它还会自动生成漂亮格式的帮助页面:
$ python hello.py --help
Usage: hello.py [OPTIONS]
Simple program that greets NAME for a total of COUNT times.
Options:
--count INTEGER Number of greetings.
--name TEXT The person to greet.
--help Show this message and exit.
几乎每个人都在使用getopt
以下是文档的示例代码:
import getopt, sys
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="])
except getopt.GetoptError:
# print help information and exit:
usage()
sys.exit(2)
output = None
verbose = False
for o, a in opts:
if o == "-v":
verbose = True
if o in ("-h", "--help"):
usage()
sys.exit()
if o in ("-o", "--output"):
output = a
总之,这就是它的工作原理。
你有两种类型的选项。那些接收参数的和那些就像开关一样。
sys.argv
在很大程度上类似于 C 中的 char** argv
。就像在 C 中一样,跳过第一个元素,即程序的名称,并仅解析参数:sys.argv[1:]
Getopt.getopt
将根据您在参数中给出的规则进行解析。
"ho:v"
这里描述了短参数:-ONELETTER
。 :
表示 -o
接受一个参数。
最后,["help", "output="]
描述了长参数(--MORETHANONELETTER
)。
输出后面的 =
再次表示输出接受一个参数。
结果是一个选项和参数的列表
如果一个选项不接受任何参数(就像这里的 --help
),则 arg
部分为空字符串。
然后通常希望在此列表上循环并测试选项名称,就像示例中一样。
我希望这能帮到你。
getopt
的弃用,这个答案已经过时了。 - shuttle87getopt
仍未被弃用... 但是它的文档指出,它主要是为熟悉C语言getopt()
函数的用户提供的,并承认对于其他用户来说,使用argparse
可能是更好的解决方案,可以"编写更少的代码并获得更好的帮助和错误消息"。 - Skippy le Grand Gourou使用附带于标准库的optparse
。例如:
#!/usr/bin/env python
import optparse
def main():
p = optparse.OptionParser()
p.add_option('--person', '-p', default="world")
options, arguments = p.parse_args()
print 'Hello %s' % options.person
if __name__ == '__main__':
main()
然而,自Python 2.7起optparse已被弃用,请参见:为什么要使用argparse而不是optparse?
轻量级命令行参数默认值
虽然 argparse
很棒,对于完全记录的命令行开关和高级功能也是正确答案,但您可以使用函数参数默认值来处理非常简单的位置参数。
import sys
def get_args(name='default', first='a', second=2):
return first, int(second)
first, second = get_args(*sys.argv)
print first, second
'name'参数用于捕获脚本名称,但不会被使用。测试输出的样式如下:
> ./test.py
a 2
> ./test.py A
A 2
> ./test.py A 20
A 20
对于我只需要一些默认值的简单脚本,我发现这已经足够了。您可能还希望在返回值或命令行值中包括一些类型转换,以确保它们不全是字符串。
如果您需要在Win32(2K、XP等)上获取Unicode参数,以下内容可能会有所帮助:
from ctypes import *
def wmain(argc, argv):
print argc
for i in argv:
print i
return 0
def startup():
size = c_int()
ptr = windll.shell32.CommandLineToArgvW(windll.kernel32.GetCommandLineW(), byref(size))
ref = c_wchar_p * size.value
raw = ref.from_address(ptr)
args = [arg for arg in raw]
windll.kernel32.LocalFree(ptr)
exit(wmain(len(args), args))
startup()
Argparse的代码可能比实际实现代码还要长!
我发现大多数流行的参数解析选项存在这样一个问题:如果您的参数只是适度的话,为了记录它们,所编写的代码就会与提供的好处不成比例。
在参数解析场景中,一个相对较新的选择(我认为)是plac。
它与argparse有一些公认的权衡,但使用内联文档并简单地包装main()
类型函数:
def main(excel_file_path: "Path to input training file.",
excel_sheet_name:"Name of the excel sheet containing training data including columns 'Label' and 'Description'.",
existing_model_path: "Path to an existing model to refine."=None,
batch_size_start: "The smallest size of any minibatch."=10.,
batch_size_stop: "The largest size of any minibatch."=250.,
batch_size_step: "The step for increase in minibatch size."=1.002,
batch_test_steps: "Flag. If True, show minibatch steps."=False):
"Train a Spacy (http://spacy.io/) text classification model with gold document and label data until the model nears convergence (LOSS < 0.5)."
pass # Implementation code goes here!
if __name__ == '__main__':
import plac; plac.call(main)