【问题标题】:Optional argument for each positional argument每个位置参数的可选参数
【发布时间】:2013-01-18 16:06:29
【问题描述】:

使用 argparse(或其他东西?)我希望每个位置参数都有一个带有默认值的可选参数。

参数如下:

script.py arg1 arg2 -o 1 arg3 -o 2 arg4 arg5

我希望它把它解析成可用的东西,比如位置参数列表和可选参数列表填充默认值。例如如果上例中可选的默认值为 0:

positional = [arg1, arg2, arg3, arg4, arg5]
optional = [0, 1, 2, 0, 0]

换句话说,parser.add_argument('-o', action='append') 不是我想要的,因为我丢失了位置参数,每个可选参数都关联到。

【问题讨论】:

  • 你知道你会有多少个位置参数吗?
  • 没有。无论有多少,我都想遍历参数。

标签: python argparse


【解决方案1】:

这是我整理的一个简单的技巧,可能是一个合理的起点:

import argparse

class PositionalAction(argparse.Action):
    def __call__(self,parser,namespace,values,option_string=None):
        lst = getattr(namespace,self.dest)
        lst.append(values)
        parser.last_positional_values = lst
        all_positional = getattr(namespace,'all_positional',[])
        all_positional.append(lst)
        namespace.all_positional = all_positional

class AssociateAction(argparse.Action):
    def __call__(self,parser,namespace,values,option_string=None):
        try:
            parser.last_positional_values.append(values)
        except AttributeError:
            pass

parser = argparse.ArgumentParser()
parser.add_argument('-o',action=AssociateAction,dest=argparse.SUPPRESS)
junk,unknown = parser.parse_known_args()

for i,_ in enumerate(unknown):
    parser.add_argument('arg%d'%i,action=PositionalAction,default=[])

print parser.parse_args()

它正在发挥作用:

temp $ python test1.py foo -o 1 bar -o 2 baz qux -o 4
Namespace(all_positional=[['foo', '1'], ['bar', '2'], ['baz'], ['qux', '4']], arg0=['foo', '1'], arg1=['bar', '2'], arg2=['baz'], arg3=['qux', '4'])

这个问题有一些挑战。首先,您想接受任意数量的位置参数—— argparse 不喜欢这样。 argparse 想预先知道会发生什么。解决方案是构建解析器并解析命令行,但告诉 argparse 仅解析已知参数(在这种情况下,非位置 -o 参数都被静默解析,但“位置”参数不被解析.)。 parse_known_args 非常适合此操作,因为它以 (namespace_of_parsed_stuff, uknown_args) 的形式返回一个元组。所以现在我们知道了未知的参数——我们只需要为每个解析器添加一个位置参数来让 parse_args 满意。

现在,自定义操作实际上在做什么?当找到位置参数时(在第二遍),我们得到默认值(这是一个列表)并将值添加到该列表中(以下我将其称为“值”列表)。然后我们使用对“值”列表的引用来修改 解析器。我们还从命名空间中获取“all_positional”列表。如果它没有那个属性,我们只会得到一个空列表。我们将“value”列表添加到“all_positional”列表中,并将其放回命名空间。

现在,当我们点击-o 标志时,我们查看解析器以获取“值”列表,并将附加值添加到该列表中。我们可以在完全不接触解析器的情况下做同样的事情......(我们可以查看namespace.all_positional[-1] -- 它与parser.last_positional_values 是同一个列表)。

【讨论】:

  • 你制作的这个魔法似乎可以达到我想要的效果(或足够接近),但我需要一段时间才能完全理解你做了什么。无论如何,谢谢!
  • 我将添加一些关于正在发生的事情的 cmets,希望能帮助它更容易理解。
  • 别担心,这些误解肯定与我缺乏专业知识有关,而不是缺乏清晰度。
【解决方案2】:

自己简单地单步执行 sys.argv 怎么样。您似乎不需要 argparse 提供的额外功能。例如:

argv='script.py arg1 arg2 -o 1 arg3 -o 2 arg4 arg5'.split()
pos=[]
opt=[]
i=1
while i<len(argv):
    a=argv[i]
    if a[:2]!='-o':
        pos.append(a)
        opt.append(0)
    else:
        i += 1
        opt[-1]=argv[i]
    i += 1

【讨论】:

    【解决方案3】:

    使用optparse,稍微复杂一点就很强大:

    op = optparse.OptionParser(usage=usage)
    
    op.add_option('-c','--cmd',dest='cmd',help="""Command to run. Mutually exclusive with -s. You can use string ${ADDR} to have it replaced with specified host address in the command. """)
    
    op.add_option('-s','--script',dest='script',help="""Script file to run remotely. Mutually exclusive with -c. A script can have its own arguments; specify the whole command in doublequotes, like "script -arg arg".""")
    
    op.add_option('-l','--replicate-owner',dest='replicateowner',action="store_true",help="""Replicate (symbolic) owner and (symbolic) group of the file on the remote host, if possible. If remote account with username the same as local account does not exist on remote host, this will silently fail.""")
    
    # parse cmdline options
    (opts, args) = op.parse_args()
    

    opts 为您命名 args,args 为您提供位置 args。

    您可以让位置参数取值或设置 true 或 false 以及更多 IIRC。

    【讨论】:

    • 这没有回答具体问题。发帖人似乎知道如何使用 {opt,arg}parse。
    猜你喜欢
    • 2023-04-02
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 2018-02-18
    • 2011-05-27
    • 2019-11-09
    相关资源
    最近更新 更多