1

我需要编写一个命令行应用程序,比如 shell。所以它将包括命令等。问题是我不知道如何将参数传递给模块中的函数。例如:

用户写道:function1 folder1 程序现在应该将 'folder1' 参数传递给 function1 函数,并运行它。但它还必须支持具有不同参数的其他功能,例如:

用户输入:function2 folder2 --exampleparam

如何使它工作?我的意思是,我可以只编写一个模块,将其导入 python 并使用 python 控制台,但事实并非如此。我需要一个接受命令输入并运行它的脚本。

我尝试使用 eval(),但这并不能解决 params 的问题。或者也许是这样,但我没有看到?

4

6 回答 6

7

问题的第一部分——解析命令行——可以用argparse来解决。

第二部分——将函数的字符串名称转换为函数调用——可以使用exec或从字符串映射到函数对象的调度 dict 来完成。

我建议不要使用exec它,因为允许用户从命令行调用任意 Python 函数可能很危险。相反,制作一个允许功能的白名单:

import argparse


def foo(path):
    print('Running foo(%r)' % (path, ))


def bar(path):
    print('Running bar(%r)' % (path, ))

dispatch = {
    'foo': foo,
    'bar': bar,
}

parser = argparse.ArgumentParser()
parser.add_argument('function')
parser.add_argument('arguments', nargs='*')
args = parser.parse_args()

dispatch[args.function](*args.arguments)

% test.py foo 1
Running foo('1')
% test.py bar 2
Running bar('2')
% test.py baz 3
KeyError: 'baz'

当命令输入到命令行本身时,上述方法有效。如果命令被输入到stdin中,那么我们需要做一些不同的事情。

一个简单的方法是调用raw_inputstdin. 然后我们可以使用 argparse 解析字符串,就像我们上面所做的那样:

shmod.py

import argparse


def foo(path):
    print('Running foo(%r)' % (path, ))


def bar(path):
    print('Running bar(%r)' % (path, ))

dispatch = {
    'foo': foo,
    'bar': bar,
}

def parse_args(cmd):
    parser = argparse.ArgumentParser()
    parser.add_argument('function')
    parser.add_argument('arguments', nargs='*')
    args = parser.parse_args(cmd.split())
    return args

主.py

import shmod

while True:
    cmd = raw_input('> ')
    args = shmod.parse_args(cmd)
    try:
        shmod.dispatch[args.function](*args.arguments)
    except KeyError:
        print('Invalid input: {!r}'.format(cmd))

另一种更复杂的处理方法是使用cmd 模块,正如@chepner 在评论中提到的那样。

from cmd import Cmd


class MyInterpreter(Cmd):

    prompt = '> '

    def do_prompt(self, line):
        "Change the interactive prompt"
        self.prompt = line + ': '

    def do_EOF(self, line):
        return True

    def do_foo(self, line):
        print('Running foo {l}'.format(l=line))

    def do_bar(self, line):
        print('Running bar {l}'.format(l=line))

if __name__ == '__main__':
    MyInterpreter().cmdloop()

有关如何使用 cmd 模块的更多信息,请参阅Doug Hellman 的优秀教程。


运行上面的代码会产生如下结果:

% test.py
> foo 1
Running foo 1
> foo 1 2 3
Running foo 1 2 3
> bar 2
Running bar 2
> baz 3
*** Unknown syntax: baz 3
于 2013-01-25T13:32:08.547 回答
2

optparse自 python 2.7 以来已被弃用,无论如何 argparse 更加灵活。unutbu 的方法是安全的,但是如果您提供白名单,我建议您让用户知道接受哪些功能

dispatch = {
    'foo': foo,    
    'bar': bar,
}

parser = argparse.ArgumentParser()
parser.add_argument('function', choices=dispatch.keys() )

仅供参考:如果解析不是太复杂,docopt看起来像一个非常好的包

于 2013-01-25T13:45:17.660 回答
1

sys.argv怎么样?有关更高级的内容,请查看argsparseoptparse现在似乎贬值了,但是这里有很多关于这个问题的答案。

于 2013-01-25T13:18:16.367 回答
1

看看 python 中的optparse模块。这正是您需要的:

http://docs.python.org/2/library/optparse.html

或者您可以编写自己的自定义 opt-parser(虽然简约)

def getopts(argv):
   opts = {}
   while argv:
      if argv[0][0] == '-': # find "-name value" pairs
         opts[argv[0]] = argv[1] # dict key is "-name" arg
         argv = argv[2:]
      else:
         argv = argv[1:]
   return opts

if __name__ == '__main__':
from sys import argv # example client code
myargs = getopts(argv)
# DO something based on your logic here

但如果您的脚本需要在 python 3 及更高版本上运行,您需要考虑argparse模块。\

希望有帮助。

于 2013-01-25T13:25:02.863 回答
0

看看optparse。这可以帮助将 shell 样式参数传递和接收到 python 脚本。

更新:显然optparse现在已弃用,argparse现在是解析命令行参数的首选选项。

于 2013-01-25T13:17:39.307 回答
0
import sys

def main(arg):
    return arg

print main(sys.argv[1])

其中 sys.argv[0] 是您正在运行的 .py 文件,之后的所有文件都是每个参数。您可以检查列表的长度,然后遍历它,并根据需要解析它们并将正确的东西传递给每个函数

于 2013-01-25T13:20:36.977 回答