在Python中处理前缀表示法的命令行参数
我正在尝试在Python中解析一个命令行,格式如下:
$ ./command -o option1 arg1 -o option2 arg2 arg3
换句话说,这个命令可以接受无限数量的参数,每个参数前面可以选择性地加上一个 -o
选项,这个选项是专门针对该参数的。我觉得这叫做“前缀表示法”。
在Bourne shell中,我会这样做:
while test -n "$1"
do
if test "$1" = '-o'
then
option="$2"
shift 2
fi
# Work with $1 (the argument) and $option (the option)
# ...
shift
done
在查看了一些Bash的教程后,这似乎是大家普遍接受的写法,所以我猜Bash是为了这种方式的命令行参数进行了优化。
我想在Python中实现这个模式,最初我想用 pop()
,因为这基本上是一个栈操作。但我猜这在Python中可能不太好用,因为 sys.argv
中的参数顺序不对,得像处理队列那样处理(也就是从左边弹出)。我听说在Python中,列表并不适合用作队列。
所以,我的想法是:把 argv
转换成 collections.deque
,然后用 popleft()
;或者用 reverse()
反转 argv
,然后用 pop()
;或者也许直接处理整数列表的索引。
有没有人知道更好的方法?如果没有,我的这些想法中哪一个在Python中是最佳实践呢?
6 个回答
在Python中,如果你想实现类似于Bourne/Bash中的“shift”功能,可以先导入sys模块,然后把sys.argv[1:]的内容赋值给一个变量,比如叫“args”。这样你就可以用args = args[1:]来向左移动一次,或者用更大的数字来移动多次。需要注意的是,参数的索引是从0开始的,而不是1。上面的例子可能看起来像这样:
import sys
args = sys.argv[1:]
while len(args):
if args[0] == '-o':
option = args[1]
args = args[2:] # shift 2
# Work with args[0] (the argument) and option (the option)
# ...
args = args[1:] # shift
你可以这样做:
argv.pop(0)
这样可以把第一个元素拿出来并返回。不过,这样做可能效率不高。也许吧。我不太确定 argv
是怎么实现的。(再说了,如果效率真的那么重要,那你为什么还在用 Python 呢?)
不过,更符合 Python 风格的做法是遍历这个列表,而不是把元素弹出。可以这样做:
o_flag = False
for a in argv:
if a == '-o':
o_flag = True
continue
# do whatever
o_flag = False
另外,我觉得 optparse
模块也值得一提;它在处理 Python 程序中的选项和参数时非常常用,虽然对于这个任务来说可能有点过于复杂,因为你已经有几个完全能用的解决方案了。
另一个标准库模块:argparse
p = argparse.ArgumentParser()
p.add_argument('-o', action='append')
for i in range(1, 4): p.add_argument('arg%d' % i)
args = p.parse_args('-o option1 arg1 -o option2 arg2 arg3'.split())
print args
# -> Namespace(arg1='arg1', arg2='arg2', arg3='arg3', o=['option1', 'option2'])