解析 Python 命令行参数的最简单、最简单、最灵活的方法或库是什么?
15 回答
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
. 有关更多信息,请参阅此答案。
正如其他人指出的那样,您最好使用 optparse 而不是 getopt。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
5 行 Python 代码,向您展示基础知识。
将其保存在 sample.py 中,然后运行一次
python sample.py
和一次
python sample.py --query myquery
除此之外,您会发现 optparse 非常容易扩展。在我的一个项目中,我创建了一个 Command 类,它允许您轻松地将子命令嵌套在命令树中。它大量使用 optparse 将命令链接在一起。这不是我可以用几行轻松解释的东西,但请随意在我的存储库中浏览主类,以及使用它的类和选项解析器
使用文档
自 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)
所以就是这样:2行代码加上你的文档字符串,这是必不可少的,你的参数被解析并在你的参数对象中可用。
使用蟒蛇火
自 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
我更喜欢点击。它抽象了管理选项并允许“(...)以可组合的方式创建漂亮的命令行界面,并使用尽可能少的代码”。
这是示例用法:
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
)。=
after 输出再次意味着输出接受一个参数。
结果是一对(选项,参数)的列表
如果一个选项不接受任何参数(如--help
这里),则该arg
部分是一个空字符串。然后,您通常希望在此列表上循环并测试示例中的选项名称。
我希望这对你有所帮助。
使用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)
我更喜欢 optparse 而不是 getopt。它是非常声明性的:你告诉它选项的名称和它们应该具有的效果(例如,设置一个布尔字段),它会给你一个根据你的规范填充的字典。
我认为大型项目的最佳方法是 optparse,但如果您正在寻找一种简单的方法,也许http://werkzeug.pocoo.org/documentation/script适合您。
from werkzeug import script
# actions go here
def action_foo(name=""):
"""action foo does foo"""
pass
def action_bar(id=0, title="default title"):
"""action bar does bar"""
pass
if __name__ == '__main__':
script.run()
所以基本上每个函数 action_* 都暴露在命令行中,并且免费生成一个很好的帮助消息。
python foo.py
usage: foo.py <action> [<options>]
foo.py --help
actions:
bar:
action bar does bar
--id integer 0
--title string default title
foo:
action foo does foo
--name string
consoleargs值得在这里提及。这是非常容易使用。看看这个:
from consoleargs import command
@command
def main(url, name=None):
"""
:param url: Remote URL
:param name: File name
"""
print """Downloading url '%r' into file '%r'""" % (url, name)
if __name__ == '__main__':
main()
现在在控制台中:
% python demo.py --help
Usage: demo.py URL [OPTIONS]
URL: Remote URL
Options:
--name -n File name
% python demo.py http://www.google.com/
Downloading url ''http://www.google.com/'' into file 'None'
% python demo.py http://www.google.com/ --name=index.html
Downloading url ''http://www.google.com/'' into file ''index.html''
这是一种方法,而不是库,似乎对我有用。
这里的目标是简洁,每个参数由一行解析,args 排列以提高可读性,代码简单且不依赖任何特殊模块(仅 os + sys),优雅地警告丢失或未知参数,使用一个简单的 for/range() 循环,并在 python 2.x 和 3.x 中工作
显示的是两个切换标志(-d、-v)和两个由参数控制的值(-i xxx 和 -o xxx)。
import os,sys
def HelpAndExit():
print("<<your help output goes here>>")
sys.exit(1)
def Fatal(msg):
sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
sys.exit(1)
def NextArg(i):
'''Return the next command line argument (if there is one)'''
if ((i+1) >= len(sys.argv)):
Fatal("'%s' expected an argument" % sys.argv[i])
return(1, sys.argv[i+1])
### MAIN
if __name__=='__main__':
verbose = 0
debug = 0
infile = "infile"
outfile = "outfile"
# Parse command line
skip = 0
for i in range(1, len(sys.argv)):
if not skip:
if sys.argv[i][:2] == "-d": debug ^= 1
elif sys.argv[i][:2] == "-v": verbose ^= 1
elif sys.argv[i][:2] == "-i": (skip,infile) = NextArg(i)
elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
elif sys.argv[i][:2] == "-h": HelpAndExit()
elif sys.argv[i][:1] == "-": Fatal("'%s' unknown argument" % sys.argv[i])
else: Fatal("'%s' unexpected" % sys.argv[i])
else: skip = 0
print("%d,%d,%s,%s" % (debug,verbose,infile,outfile))
NextArg() 的目标是在检查丢失的数据时返回下一个参数,并且在使用 NextArg() 时“skip”跳过循环,将标志解析为一个衬垫。
我扩展了 Erco 的方法以允许必需的位置参数和可选参数。这些应该在 -d、-v 等参数之前。
可以分别使用 PosArg(i) 和 OptArg(i, default) 检索位置和可选参数。当找到一个可选参数时,搜索选项(例如 -i)的开始位置向前移动 1 以避免导致“意外”致命。
import os,sys
def HelpAndExit():
print("<<your help output goes here>>")
sys.exit(1)
def Fatal(msg):
sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
sys.exit(1)
def NextArg(i):
'''Return the next command line argument (if there is one)'''
if ((i+1) >= len(sys.argv)):
Fatal("'%s' expected an argument" % sys.argv[i])
return(1, sys.argv[i+1])
def PosArg(i):
'''Return positional argument'''
if i >= len(sys.argv):
Fatal("'%s' expected an argument" % sys.argv[i])
return sys.argv[i]
def OptArg(i, default):
'''Return optional argument (if there is one)'''
if i >= len(sys.argv):
Fatal("'%s' expected an argument" % sys.argv[i])
if sys.argv[i][:1] != '-':
return True, sys.argv[i]
else:
return False, default
### MAIN
if __name__=='__main__':
verbose = 0
debug = 0
infile = "infile"
outfile = "outfile"
options_start = 3
# --- Parse two positional parameters ---
n1 = int(PosArg(1))
n2 = int(PosArg(2))
# --- Parse an optional parameters ---
present, a3 = OptArg(3,50)
n3 = int(a3)
options_start += int(present)
# --- Parse rest of command line ---
skip = 0
for i in range(options_start, len(sys.argv)):
if not skip:
if sys.argv[i][:2] == "-d": debug ^= 1
elif sys.argv[i][:2] == "-v": verbose ^= 1
elif sys.argv[i][:2] == "-i": (skip,infile) = NextArg(i)
elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
elif sys.argv[i][:2] == "-h": HelpAndExit()
elif sys.argv[i][:1] == "-": Fatal("'%s' unknown argument" % sys.argv[i])
else: Fatal("'%s' unexpected" % sys.argv[i])
else: skip = 0
print("Number 1 = %d" % n1)
print("Number 2 = %d" % n2)
print("Number 3 = %d" % n3)
print("Debug = %d" % debug)
print("verbose = %d" % verbose)
print("infile = %s" % infile)
print("outfile = %s" % outfile)