【问题标题】:How do you convert command line args in python to a dictionary?如何将 python 中的命令行参数转换为字典?
【发布时间】:2012-10-09 19:59:55
【问题描述】:

我正在编写一个应用程序,它接受任意命令行参数,然后将它们传递给 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 具有执行此操作的功能...

【问题讨论】:

  • argparse 完全不同,它用于定义命令行界面。我正在尝试解析任意命令行界面。每次调用这个脚本都会有不同的参数。
  • 认为使用 argparse 仍然可以做到这一点。如果您不想使用它,那么 AFAIK 您别无选择,只能自己为参数编写解析器。
  • 是的,我也不知道如何使用标准库解析任意参数...
  • 5年后这个问题还没有解决吗?我需要写这个东西吗??

标签: python command-line argv sys


【解决方案1】:

你可以这样使用:

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]

之后。

【讨论】:

    【解决方案2】:

    如果您真的想编写自己的东西而不是适当的命令行解析库,那么对于您的输入,这应该可以工作:

    dict(map(lambda x: x.lstrip('-').split('='),sys.argv[1:]))
    

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

    【讨论】:

    • 这不会给出想要的结果。以 OP 为例,arg1 不会映射到 14,而只会映射到 4
    【解决方案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
    

    【讨论】:

      【解决方案4】:

      这样的?

      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]     
      

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

      【讨论】:

      • 我建议使用defaultdict 作为变量argsdict。这样你就可以摆脱in 测试并且可以不用担心地追加。它使您的代码更加简洁和富有表现力,因此更加pythonic。
      【解决方案5】:

      这是我今天用的,它占:

      --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
      

      【讨论】:

        【解决方案6】:

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

        ?

        编辑:

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

        【讨论】:

        • 如何扩展 argparse,例如,解析任意参数?想不出来。
        【解决方案7】:

        或类似的东西)对不起,如果这很愚蠢,我是新手:)

        $ 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()
        

        【讨论】:

          猜你喜欢
          • 2019-06-02
          • 2021-05-30
          • 2020-06-27
          • 1970-01-01
          • 2014-11-07
          • 2017-11-08
          • 1970-01-01
          相关资源
          最近更新 更多