【问题标题】:Python - passing parameters in a command line appPython - 在命令行应用程序中传递参数
【发布时间】:2013-01-25 23:12:29
【问题描述】:

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

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

用户输入:function2 folder2 --exampleparam

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

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

【问题讨论】:

    标签: python parameters python-2.7


    【解决方案1】:

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

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

    我建议为此使用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
    

    ma​​in.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 module,正如@chepner 在 cmets 中提到的那样。

    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's excellent tutorial.


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

    % 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
    

    【讨论】:

    • 对于第二部分,也请看一下cmd 模块。
    • 这对我有用,但我仍然无法弄清楚如何从另一个脚本实际启动命令。如果我将它放入模块中的函数中,并像这样调用它:module.function,则什么也不会发生。但是,如果我这样做:module.function 1,我会收到语法错误。使用参数 module.function(param) 调用它没有意义,因为该函数没有任何参数。我是 Python 新手,不幸的是还没有真正了解它。
    • 尝试import module; module.function() 调用在module 中定义的function
    • 这正是我所做的,但这不允许我将任何参数传递给解析器。相反,它只是调用函数,没有任何参数,在这种情况下,它什么都不做。在示例中,您将使用命令行中的参数运行脚本。我需要以这种方式运行它,但要从另一个脚本中运行。
    • 好的,我不明白你在问什么。你能发布你的代码(两个脚本)和你想要发生的事情吗?
    【解决方案2】:

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

    dispatch = {
        'foo': foo,    
        'bar': bar,
    }
    
    parser = argparse.ArgumentParser()
    parser.add_argument('function', choices=dispatch.keys() )
    

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

    【讨论】:

      【解决方案3】:

      sys.argv 怎么样?如需更高级的内容,请查看argsparseoptparse 现在似乎贬值了,但这里有一个 lot of answers 关于这个问题。

      【讨论】:

        【解决方案4】:

        看看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 模块。\

        希望对您有所帮助。

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            【解决方案6】:
            import sys
            
            def main(arg):
                return arg
            
            print main(sys.argv[1])
            

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2020-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-01-28
              相关资源
              最近更新 更多