如何将Python中的命令行参数转换为字典?

14

我正在编写一个应用程序,该程序接收任意的命令行参数,并将它们传递给一个Python函数:

$ myscript.py --arg1=1 --arg2=foobar --arg1=4

然后在 myscript.py 文件中:

import sys
argsdict = some_function(sys.argv)

其中argsdict的形式如下:

{'arg1': ['1', '4'], 'arg2': 'foobar'}

我确定有某个库可以做到这一点,但我找不到任何东西。

编辑: argparse/getopt/optparse不是我要找的。这些库用于定义每次调用都相同的接口。我需要能够处理任意参数。

除非argparse/optparse/getopt具有此功能...


1
http://docs.python.org/dev/library/argparse.html - John Vinyard
1
argparse是完全不同的,它用于定义命令行接口。我正在尝试解析任意的命令行接口。每次调用此脚本时,参数都会不同。 - priestc
认为使用argparse仍然可以实现这一点。如果您不想使用它,那么据我所知,您只能自己编写参数解析器。 - Andrew Gorcester
1
是的,我也无法弄清如何使用标准库解析任意参数... - bumpkin
3
五年过去了,这个问题还没有解决吗?我需要写这个东西吗? - prismofeverything
7个回答

3
您可以使用类似以下的内容: myscript.py
import sys
from collections import defaultdict

d=defaultdict(list)
for k, v in ((k.lstrip('-'), v) for k,v in (a.split('=') for a in sys.argv[1:])):
    d[k].append(v)

print dict(d)

结果:

C:\>python myscript.py  --arg1=1 --arg2=foobar --arg1=4
{'arg1': ['1', '4'], 'arg2': ['foobar']}

注意:值始终是一个列表,我认为这样更加一致。如果您真的想要最终字典,它将是:
{'arg1': ['1', '4'], 'arg2': 'foobar'}

那么,您只需运行以下命令。
for k in (k for k in d if len(d[k])==1):
    d[k] = d[k][0]

之后。


3

这里举一个使用argparse的例子,虽然这有点困难。我不会称之为完整的解决方案,但起码是一个很好的开端。

class StoreInDict(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        d = getattr(namespace, self.dest)
        for opt in values:
            k,v = opt.split("=", 1)
            k = k.lstrip("-")
            if k in d:
                d[k].append(v)
            else:
                d[k] = [v]
        setattr(namespace, self.dest, d)

# Prevent argparse from trying to distinguish between positional arguments
# and optional arguments. Yes, it's a hack.
p = argparse.ArgumentParser( prefix_chars=' ' )

# Put all arguments in a single list, and process them with the custom action above,
# which convertes each "--key=value" argument to a "(key,value)" tuple and then
# merges it into the given dictionary.
p.add_argument("options", nargs="*", action=StoreInDict, default=dict())

args = p.parse_args("--arg1=1 --arg2=foo --arg1=4".split())
print args.options

1

我今天使用的是以下内容,它包括:

--key=val--key-key-key val

def clean_arguments(args):
    ret_args = defaultdict(list)

    for index, k in enumerate(args):
        if index < len(args) - 1:
            a, b = k, args[index+1]
        else:
            a, b = k, None

        new_key = None

        # double hyphen, equals
        if a.startswith('--') and '=' in a:
            new_key, val = a.split('=')

        # double hyphen, no equals
        # single hyphen, no arg
        elif (a.startswith('--') and '=' not in a) or \
                (a.startswith('-') and (not b or b.startswith('-'))):
            val = True

        # single hypen, arg
        elif a.startswith('-') and b and not b.startswith('-'):
            val = b

        else:
            if (b is None) or (a == val):
                continue

            else:
                raise ValueError('Unexpected argument pair: %s, %s' % (a, b))

        # santize the key
        key = (new_key or a).strip(' -')
        ret_args[key].append(val)

    return ret_args

1

类似这样的东西?

import sys

argsdict = {}

for farg in sys.argv:
    if farg.startswith('--'):
        (arg,val) = farg.split("=")
        arg = arg[2:]

        if arg in argsdict:
            argsdict[arg].append(val)
        else:
            argsdict[arg] = [val]     

与指定的略有不同,该值始终为列表。

2
我建议在变量argsdict中使用defaultdict。这样,您就可以摆脱in测试并且可以放心地进行附加操作。它使您的代码更加简洁和表达性更强,因此更符合Pythonic风格。 - halex

0
或者类似这样的) 抱歉,如果这很愚蠢,我是新手 :) $ python3 Test.py a 1 b 2 c 3
import sys

def somefunc():
    keys = []
    values = []
    input_d = sys.argv[1:]

    for i in range(0, len(input_d)-1, 2):
        keys.append(input_d[i])
        values.append(input_d[i+1])

    d_sys = dict(zip(keys, values))

somefunc()

0

我可以问一下,为什么你要重写(一堆)轮子,当你已经有了:

?

编辑:

针对您的编辑,optparse / argparse(后者仅适用于> =2.7)足够灵活以扩展以满足您的需求,同时保持一致的界面(例如,用户希望能够使用--arg=value--arg value-a value-avalue等等。使用预先存在的库,您不必担心支持所有这些语法等)。


13
你如何扩展 argparse 来解析任意参数?我想不出来。 - bumpkin

-1
如果你真的想要自己编写而不是使用一个合适的命令行解析库,那么对于你的输入,这应该可以工作:
dict(map(lambda x: x.lstrip('-').split('='),sys.argv[1:]))

您需要添加一些内容来捕获没有“=”的参数。


这样做不会得到期望的结果。使用 OPs 的示例,arg1 不会映射到 14,而只会映射到 4 - sloth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接