Python argparse 字典 arg

Posted

技术标签:

【中文标题】Python argparse 字典 arg【英文标题】:Python argparse dict arg 【发布时间】:2015-07-11 05:52:31 【问题描述】:

我想从命令行接收dict(str -> str) 参数。 argparse.ArgumentParser 提供吗?还是其他图书馆?

对于命令行:

program.py --dict d --key key1 --value val1 --key key2 --value val2

我期待以下字典:

d = "key1": "val1", "key2": "val2"

【问题讨论】:

你是在做参数解析还是什么?将其收集到 dict 似乎并没有什么意义。 @skyline75489。是的。我解析 d 参数。为什么列表可以是参数,而字典不能.. 参数可能非常复杂。它可以是可选的或必需的、位置的或非位置的、需要值或不需要值。我想添加dict 支持会让事情变得更加复杂。 不如program.py --opt1 k1=v1,k2=v2,k3=v3好吗? 另一种选择是将值作为(引用的)JSON 字符串输入。 【参考方案1】:

这是另一个使用自定义操作的解决方案,如果您想以逗号分隔一起指定字典键对 --

import argparse
import sys
parser = argparse.ArgumentParser(description='parse key pairs into a dictionary')

class StoreDictKeyPair(argparse.Action):
     def __call__(self, parser, namespace, values, option_string=None):
         my_dict = 
         for kv in values.split(","):
             k,v = kv.split("=")
             my_dict[k] = v
         setattr(namespace, self.dest, my_dict)

parser.add_argument("--key_pairs", dest="my_dict", action=StoreDictKeyPair, metavar="KEY1=VAL1,KEY2=VAL2...")

args = parser.parse_args(sys.argv[1:])
print args

跑步:

python parse_kv.py --key_pairs 1=2,a=bbb,c=4 --key_pairs test=7,foo=bar

输出:

Namespace(my_dict='1': '2', 'a': 'bbb', 'c': '4', 'test': '7', 'foo': 'bar')

如果你想在字符串中使用 nargs 而不是逗号分隔的值:

class StoreDictKeyPair(argparse.Action):
     def __init__(self, option_strings, dest, nargs=None, **kwargs):
         self._nargs = nargs
         super(StoreDictKeyPair, self).__init__(option_strings, dest, nargs=nargs, **kwargs)
     def __call__(self, parser, namespace, values, option_string=None):
         my_dict = 
         print "values: ".format(values)
         for kv in values:
             k,v = kv.split("=")
             my_dict[k] = v
         setattr(namespace, self.dest, my_dict)

parser.add_argument("--key_pairs", dest="my_dict", action=StoreDictKeyPair, nargs="+", metavar="KEY=VAL")

args = parser.parse_args(sys.argv[1:])
print args

跑步

python arg_test4.py --key_pairs 1=2 a=bbb c=4 test=7 foo=bar

输出:

values: ['1=2', 'a=bbb', 'c=4', 'test=7', 'foo=bar']
Namespace(my_dict='1': '2', 'a': 'bbb', 'c': '4', 'test': '7', 'foo': 'bar')

【讨论】:

这绝对是最好的答案 被低估的答案。唉,我已经给了我所有的爱。 很好的答案(已经赞成),但这不会将布尔字符串解析为布尔值或作为字符串传递的其他数据类型(列表、字典)。需要评估价值。请注意!【参考方案2】:

我会使用这样的东西:

p = argparse.ArgumentParser()
p.add_argument("--keyvalue", action='append',
               type=lambda kv: kv.split("="), dest='keyvalues')

args = p.parse_args("--keyvalue foo=6 --keyvalue bar=baz".split())
d = dict(args.keyvalues)

您可以创建一个自定义操作,将已解析的键值对直接“附加”到字典中,而不是简单地累积(key, value) 元组的列表。 (我看到的是 skyline75489 所做的;我的答案不同之处在于使用带有自定义类型的单个 --keyvalue 选项,而不是单独的 --key--value 选项来指定对。)

【讨论】:

谢谢。你的答案是最好的。 我建议使用kv.split("=", 1) 来允许= 在值中并确保您最多有2 个元素。 还有:if any(len(kv) < 2 for kv in args.keyvalues): raise ValueError('Values must be given in the form "KEY=VALUE"')【参考方案3】:

只是另一种简单的方法:

parser = argparse.ArgumentParser()
parser.add_argument('--key1')
parser.add_argument('--key2')
args = parser.parse_args()
my_dict = args.__dict__

【讨论】:

不,我不想将 agruments 转换为字典。很容易做到:arguments = vars(parser.parse_args())。请用示例重新阅读问题 访问您无法控制的类的__dict__ 属性通常不是一个好习惯,因为它可能包含您不期望的元数据。【参考方案4】:

Python 以数组argv 的形式接收参数。您可以使用它在程序本身中创建字典。

import sys
my_dict = 
for arg in sys.argv[1:]:
    key, val=arg.split(':')[0], arg.split(':')[1]
    my_dict[key]=val

print my_dict

对于命令行:

python program.py key1:val1 key2:val2 key3:val3

输出:

my_dict = 'key3': 'val3', 'key2': 'val2', 'key1': 'val1'

注意:args 将是字符串,因此您必须将它们转换为存储数值。

希望对你有帮助。

【讨论】:

我认为您的解决方案还可以,但有点脏。 1. 键和值不能包含':' 2. 多个参数的顺序太难控制 我给出的不是唯一的解决方案,关键是你有一个参数列表 - ['key1', 'val1', 'key2', 'val2', 'key3', 'val3 '],因此可以使用任何逻辑获得 dict,例如:每个偶数元素(例如 pos 'i')是键,它的值将在 pos (i+1),所以只需以步长运行循环2 并存储字典。【参考方案5】:

Python 单行 argparse 字典参数argparse_dictionary.py

# $ python argparse_dictionary.py --arg_dict=1=11,2=22;3=33 --arg_dict=a=,b,c=cc,=dd,=ee=,
# Namespace(arg_dict='1': '11', '2': '22', '3': '33', 'a': '', 'c': 'cc', '': 'dd')

import argparse

arg_parser = argparse.ArgumentParser()
arg_parser.add_argument(
    '--arg_dict',
    action=type(
        '', (argparse.Action, ),
        dict(__call__=lambda self, parser, namespace, values, option_string: getattr(
            namespace, self.dest).update(
                dict([
                    v.split('=') for v in values.replace(';', ',').split(',')
                    if len(v.split('=')) == 2
                ])))),
    default=,
    metavar='KEY1=VAL1,KEY2=VAL2;KEY3=VAL3...',
)
print(arg_parser.parse_args())

【讨论】:

好点,但我很抱歉 - 这是不可读的代码。请使用 pep8。【参考方案6】:

使用变量

d = vars(parser.parse_args())

【讨论】:

感谢您的贡献。但是您的代码并不能解决问题。它只是将所有传递的参数转换为字典,但代码也应该使用未知的动态键。【参考方案7】:

解析输入的直接方式,例如:

program.py --dict d --key key1 --value val1 --key key2 --value val2

是:

parser=argparse.ArgumentParser()
parser.add_argument('--dict')
parser.add_argument('--key', action='append')
parser.add_argument('--value', action='append')
args = parser.parse_args()

应该产生(如果我的心理解析器是正确的)

args = Namespace(dict='d', key=['key1','key2'], value=['value1','value2'])

您应该可以使用以下方法构建字典:

adict = k:v for k, v in zip(args.key, args.value)

使用args.dict 将其分配给具有该名称的变量需要一些非python 技巧。最好的办法是在另一个字典中使用此名称创建一个元素。

another_dict = args.dict: adict

此解决方案不会执行太多错误检查。例如,它不能确保有相同数量的键和值。它也不会让您创建多个字典(即重复 --dict 参数)。它不需要任何特殊订单。 --dict 可能出现在 --key key1 对之后。几个--value 参数可以放在一起。

key=valuechepner 绑定在一起确实可以解决许多这些问题。

【讨论】:

【参考方案8】:

如果您只是想将 argparse 输入转换为字典,那么 Python 3.6 中有一个简单的解决方案。一个例子如下:

import argparse 

parser = argparse.ArgumentParser()
parser.add_argument('-i', '--input', help='the path to the input file')
parser.add_argument('-o', '--output', help='the path to the output file')
args = parser.parse_args()

arguments = dict(args._get_kwargs())

for k, v in arguments.items():
    print(k, v) 

给定命令行输入,例如python3 script_name.py --input 'input.txt' --output 'output.txt',代码将输出到终端:

input input.txt
output output.txt

【讨论】:

不,我不想将 agruments 转换为字典。无需使用隐藏字段即可轻松完成:arguments = vars(parser.parse_args())。请用示例重新阅读问题。 arguments = vars(parser.parse_args()) 在这种情况下,这通常是您想要的。【参考方案9】:

目前的库如argparse、docopt和click,都不支持使用dict args。我能想到的最佳解决方案是自定义argparse.Action 来支持它自己:

import argparse

class MyAction(argparse.Action):
    def __init__(self, option_strings, dest, nargs=None, **kwargs):
        super(MyAction, self).__init__(option_strings, dest, nargs, **kwargs)

    def __call__(self, parser, namespace, values, option_string=None):
        print '%r %r %r' % (namespace, values, option_string)
        value_dict = 
        values.reverse()
        while len(values) > 0:
            v = eval(values.pop()).lstrip('--') # This is like crazy hack, I know.
            k = eval(values.pop())
            value_dict[k] = v

        setattr(namespace, self.dest, value_dict)

parser = argparse.ArgumentParser()
parser.add_argument('-d', action=MyAction, nargs='*')
args = parser.parse_args('-d "--key" "key1" "--value" "val1" "--key" "key2" "--value" "val2"'.split())

print(args)

【讨论】:

以上是关于Python argparse 字典 arg的主要内容,如果未能解决你的问题,请参考以下文章

使用 argparse 和 python 接受字典作为参数 [重复]

Python argparse 字典 arg

将 Python argparse.Namespace() 视为字典的正确方法是啥?

编程54--python学习28Namespace与dict的相互转换,保存Namespace,以字典形式传入argparse的参数

通过 argparse 传递 JSON 字典和一个 char

Python+argparse+notebook