在 Python 中以前缀表示法处理命令行参数
Posted
技术标签:
【中文标题】在 Python 中以前缀表示法处理命令行参数【英文标题】:Processing command-line arguments in prefix notation in Python 【发布时间】:2011-02-19 08:52:33 【问题描述】:我正在尝试在 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()
,或者只使用int 列表索引本身。
有没有人知道更好的方法来做到这一点,否则我的哪个想法在 Python 中是最佳实践?
【问题讨论】:
【参考方案1】:在 python 中,del sys.argv[1]
与bash
中的shift
执行相同的操作。在 python 中,sys.argv
是一个列表。删除索引1
上的元素与bash
中的shift
相同。
以下示例 python 脚本将有助于跳过参数中的 -o
并考虑所有其他参数。
#!/usr/bin/python
import sys
if __name__ == '__main__':
while len(sys.argv) > 1:
if sys.argv[1] != "-o":
print sys.argv[1]
del sys.argv[1]
【讨论】:
【参考方案2】:可以通过导入 sys,然后将 sys.argv[1:] 分配给变量来获得 Bourne/Bash 中“shift”的 Python 功能等价物,例如“参数”。然后您可以使用 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
【讨论】:
【参考方案3】:另一个标准库模块: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'])
【讨论】:
我希望我知道 argparse。 Optparse 很好,但如果你希望你的参数有多个值,你必须创建自己的类。为什么 stdlib 中有这么多选项解析器?【参考方案4】:无需重新发明***:getopt
模块正是为此而设计的。如果这不符合您的需求,请尝试optparse
模块,它更灵活但更复杂。
【讨论】:
感谢您的回答。您能否举例说明如何使用 getopt 或 optparse 实现“前缀表示法”模式。我以前用过这两种方法,但我认为你只能解析“选项”,然后是“非选项”,而不是选项参数、选项参数……我需要的方式。 非选项参数不是作为列表返回的吗?来自 parser.parse_args() ?【参考方案5】:类似:
for arg in sys.argv[1:]:
# do something with arg
应该适合你。除非您期望有大量的参数,否则我会选择最简单的代码(不要太担心性能)。 argv[1:] 忽略第一个 argv 值,这将是脚本的名称。
【讨论】:
【参考方案6】:你可以的
argv.pop(0)
提取第一个元素并返回它。不过,这可能效率低下。可能是。我不确定argv
是如何在幕后实现的。 (话说回来,如果效率那很重要,你为什么要使用 Python?)
不过,更 Pythonic 的解决方案是在不弹出元素的情况下遍历列表。像这样:
o_flag = False
for a in argv:
if a == '-o':
o_flag = True
continue
# do whatever
o_flag = False
另外,我认为optparse
模块值得一提;它是处理 Python 程序中的选项和参数的标准,尽管对于这个任务来说它可能是多余的,因为你已经有了几个完美的功能解决方案。
【讨论】:
你是对的;如果性能是最重要的,我可以很容易地在 C 中实现这种模式。我想我的问题更多是关于如何实现 argv 以及如何最好地将它作为堆栈访问(因为它必须是内部堆栈)。 我的猜测是标准的 C 数组,尽管正如我所说,我不确定。如果您好奇,您可以随时查看 Python 解释器的源代码并尝试追踪数组实现。但是在实际中使用,真的无所谓。以上是关于在 Python 中以前缀表示法处理命令行参数的主要内容,如果未能解决你的问题,请参考以下文章