在Python中处理前缀表示法的命令行参数

9 投票
6 回答
9477 浏览
提问于 2025-04-15 22:41

我正在尝试在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 个回答

9

在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
9

你可以这样做:

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 程序中的选项和参数时非常常用,虽然对于这个任务来说可能有点过于复杂,因为你已经有几个完全能用的解决方案了。

7

另一个标准库模块: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'])

撰写回答