【问题标题】:Python - Pass Arguments to Different Methods from ArgparsePython - 从 Argparse 将参数传递给不同的方法
【发布时间】:2011-11-12 06:22:11
【问题描述】:

我正在编写一个相对简单的 Python 脚本,它支持几个不同的命令。不同的命令支持不同的选项,我希望能够将 argparse 解析的选项传递给指定命令的正确方法。

用法字符串如下所示:

usage: script.py [-h]

            {a, b, c}
            ...
script.py: error: too few arguments

我可以轻松调用相应的方法:

def a():
    ...

def b():
    ...

def c():
    ...

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.set_defaults(method = a)
    ...

    arguments = parser.parse_args()
    arguments.method()

但是,我必须将参数传递给这些方法,并且它们都接受不同的参数集。

目前,我只是传递 argparse 返回的 Namespace 对象,如下所示:

 def a(arguments):
     arg1 = getattr(arguments, 'arg1', None)
     ...

这似乎有点尴尬,并且使方法更难重用,因为我必须将参数作为dict 或命名空间而不是通常的参数传递。

我想以某种方式定义带有参数的方法(就像您使用普通函数一样),并且仍然能够在传递适当参数的同时动态调用它们。像这样:

def a(arg1, arg2):
    ...

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.set_defaults(method = a)
    ...

    arguments = parser.parse_args()
    arguments.method() # <<<< Arguments passed here somehow

有什么想法吗?

【问题讨论】:

    标签: python dynamic methods arguments argparse


    【解决方案1】:

    我找到了一个很好的解决方案:

    import argparse
    
    def a(arg1, arg2, **kwargs):
        print arg1
        print arg2
    
    if __name__ == "__main__":
            parser = argparse.ArgumentParser()
            parser.set_defaults(method = a)
            parser.add_argument('arg1', type = str)
            parser.add_argument('arg2', type = str)
    
            arguments = parser.parse_args()
            arguments.method(**vars(arguments))
    

    当然,如果方法的参数与 argparse 使用的参数的名称发生冲突,则存在一个小问题,尽管我认为这比传递命名空间对象并使用 getattr 更好。

    【讨论】:

      【解决方案2】:

      您可能正在尝试实现子命令提供的功能: http://docs.python.org/dev/library/argparse.html#sub-commands

      【讨论】:

      • 我正在使用子解析器,我试图避免让它们调用的方法采用“argument”参数,该参数应该是从 argparse 返回的命名空间实例。
      【解决方案3】:

      不确定这有多实用,但通过使用inspect,您可以省略函数中无关的 **kwargs 参数,如下所示:

      import argparse
      import inspect
      
      
      def sleep(seconds=0):
          print "sleeping", seconds, "seconds"
      
      def foo(a, b=2, **kwargs):
          print "a=",a
          print "b=",b
          print "kwargs=",kwargs
      
      parser = argparse.ArgumentParser()
      
      subparsers = parser.add_subparsers(title="subcommand")
      
      parser_sleep = subparsers.add_parser('sleep')
      parser_sleep.add_argument("seconds", type=int, default=0)
      parser_sleep.set_defaults(func=sleep)
      
      parser_foo = subparsers.add_parser('foo')
      parser_foo.add_argument("-a", type=int, default=101)
      parser_foo.add_argument("-b", type=int, default=201)
      parser_foo.add_argument("--wacky", default=argparse.SUPPRESS)
      parser_foo.set_defaults(func=foo)
      
      args = parser.parse_args()
      
      arg_spec = inspect.getargspec(args.func)
      if arg_spec.keywords:
          ## convert args to a dictionary
          args_for_func = vars(args)
      else:
          ## get a subset of the dictionary containing just the arguments of func
          args_for_func = {k:getattr(args, k) for k in arg_spec.args}
      
      args.func(**args_for_func)
      

      例子:

      $ python test.py sleep 23
      sleeping 23 seconds
      
      $ python test.py foo -a 333 -b 444
      a= 333
      b= 444
      kwargs= {'func': <function foo at 0x10993dd70>}
      
      $ python test.py foo -a 333 -b 444 --wacky "this is wacky"
      a= 333
      b= 444
      kwargs= {'func': <function foo at 0x10a321d70>, 'wacky': 'this is wacky'}
      

      玩得开心!

      【讨论】:

        猜你喜欢
        • 2016-09-08
        • 2018-06-27
        • 1970-01-01
        • 1970-01-01
        • 2018-10-17
        • 2018-02-25
        • 2017-10-10
        • 1970-01-01
        • 2018-11-19
        相关资源
        最近更新 更多