Argparse和复杂类型

时间:2013-09-12 08:44:54

标签: python command-line-arguments

我想为我的用户提供添加多个复杂对象的可能性,例如:一个Library对象:

  • LIBRARY_NAME
  • library_number
  • ...

为此,我所做的是设置一个带有追加操作的参数--library并向参数添加一个类型,以便它以正确的格式读取它,导致以下命令行: --library“library_name = test; library_number = 5”,库类型函数将测试并完成工作,但这不是一个很好的方法,有任何其他方法可以做我想要的吗?

我想使用这样的问题:

--library test 5

这对我看起来更好但是我想要关联的类型函数不能是一个复杂的函数,因为它在返回的数组的每个值上都被破坏了!

有什么想法吗?


我应该多解释一下我正在尝试做些什么。我正在研究工作流管理器引擎。这个指定一个属性文件,其中定义所有参数,并解析此参数列表以构建正确的argparse对象。

作为示例,我可以将我的库参数定义为之前的define:     library_name.name = ...     library_name.help = ...     library_name.type = str     library_name.required = True

library_number.name = ...
library_number.help = ...
library_number.type = int
library_number.required = True 
...

但是我希望这个对象设置的数量与用户想要的库一样多,这样我就可以为这些选项添加一个附加操作,但是用户必须以正确的顺序提供所有输入:

--library-name lib1 --library-number 1 --library-name lib2 --library-number 2

但这对用户来说并不容易,我所做的是:

--library "name=lib1;number=1" --library "name=lib2;number=2"

但这不是“漂亮”,我更喜欢这样的东西,但我仍然想检查这是否是正确的格式:

--library lib1 1 --library lib2 2

更清楚了吗?


我应该多解释一下,我改变了你给我的东西,所以用户可以--library library-name = test library-number = 5,所以不需要提供所有字段,不过我希望其中一些字段可以是必需的,但为了这样做,我需要知道一旦检查了所有参数是否已经解决了所需的参数

    class MiltipleParameters(object):
        def __init__(self, types):
            self.types = types
            self.index = None
            self.__name__ = "MiltipleParameters"
        def __call__(self, arg):
            parts = arg.split("=")
            if not self.types.has_key(parts[0]):
                raise argparse.ArgumentTypeError(parts[0] + " is an invalid flag! Available ones are: "+", ".join(self.types.keys()))
            try:
                value = self.types[parts[0]](parts[1])
            except:
                raise argparse.ArgumentTypeError("invalid " + self.types[parts[0]].__name__ + " value: '" + parts[1] + "' for sub parameter '" + parts[0] + "'")
            self.index = parts[0]
            return (parts[0], value)

这种类型采用带有param_name:类型的哈希表,我可以添加必需的字段,以便检查它。但我确实需要知道它何时结束,以检查所需的参数是否设置。 有可能吗?

4 个答案:

答案 0 :(得分:1)

您可以创建一个非常简单的状态机:

class NargsTypeChecker(object):
    def __init__(self, types):
        self.types = types
        self.index = 0
    def __repr__(self):
        return self.types[self.index].__name__
    def __call__(self, arg):
        value = self.types[self.index](arg)
        self.index = (self.index + 1) % len(self.types)
        return value

用作:

parser.add_argument('--library', nargs=3, type=NargsTypeChecker((int, float, str)))

还有一些错误输出:

$python3 complex_type.py --library lib 1 3.6
Namespace(library=['lib', 1, 3.6])
$python3 complex_type.py --library lib other 3.6
usage: complex_type.py [-h] [--library LIBRARY LIBRARY LIBRARY]
complex_type.py: error: argument --library: invalid int value: 'other'
$python3 complex_type.py --library lib 2 other
usage: complex_type.py [-h] [--library LIBRARY LIBRARY LIBRARY]
complex_type.py: error: argument --library: invalid float value: 'other'

答案 1 :(得分:0)

如果您的库名称不包含空格,您只需使用一个字符串,然后执行

library = argstring.split()

这将返回一个列表library,其中library[0]为名称,library[1]为数字。

答案 2 :(得分:0)

如果您可以接受格式: - library lib1:1 --library lib2:2

def libType(ls):
    name, num = ls.split(':')
    return name, int(num)

parser.add_argument("--library", action = "append", type=libType)
# you get: Namespace(library=[('lib1', 1), ('lib2', 2)])

如果您愿意坚持: - 图书馆lib1 1 - 图书馆lib2 2

parser.add_argument("--library", action = "append", nargs=2)
# you get: Namespace(library=[['lib1', '1'], ['lib2', '2']])

然后你必须执行额外的类型检查才能获得int而不是str。

答案 3 :(得分:0)

另一种采用自定义操作的解决方案:

import argparse

class LibAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        try: 
            lib = {'name': values[0], 'type': int(values[1])}
            if namespace.library:
                namespace.library.append(lib)
            else:
                namespace.library=[lib]
        except ValueError:
             parser.error("Problem with library: %s is not int"%(values[1])) 

parser = argparse.ArgumentParser()
parser.add_argument("--library", action = LibAction, nargs=2)
args = parser.parse_args()
print args     

您获得:

Namespace(library=[{'type': 1, 'name': 'lib1'}, {'type': 2, 'name': 'lib2'}])

如果您使用以下错误处理: - library libA a