6

我编写了一个带有一个或多个输入文件的脚本。我希望能够为脚本(A 和 B)和每个输入文件(C 和 D)分别指定选项。

用法应如下所示:

script.py [-A] [-B]  [-C] [-D] file1 [[-C] [-D] file2] ...

怎么办argparse

谢谢!

4

5 回答 5

4

如果可能,请尝试docopt。它更容易使用,并且有足够的示例可供入门。

于 2012-11-02T17:56:15.480 回答
4

我想做这个已经有一段时间了,但从来没有想过一个用例。你找到了:谢谢!

您可以通过两个阶段的 argparsing 来做到这一点。在第一阶段,您只寻找-A-B选项。

在第二阶段,您将剩余的参数拆分为片段(在本例中使用生成器函数)并调用parse_args片段:

import argparse

def fileargs(args):
    result = []
    for arg in args:
        result.append(arg)
        if not arg.startswith('-'):
            yield result
            result = []

parser = argparse.ArgumentParser()
parser.add_argument('-A', action = 'store_true')
parser.add_argument('-B', action = 'store_true')
args, unk = parser.parse_known_args()
print(args)

file_parser = argparse.ArgumentParser()
file_parser.add_argument('-C', action = 'store_true')
file_parser.add_argument('-D', action = 'store_true')
file_parser.add_argument('file')
for filearg in fileargs(unk):
    fargs = file_parser.parse_args(filearg)
    print(fargs)

然后test.py -A -B -C -D file1 -C file2产生

Namespace(A=True, B=True)
Namespace(C=True, D=True, file='file1')
Namespace(C=True, D=False, file='file2')
于 2012-11-02T18:13:26.583 回答
1

我的,这个答案很复杂:

import sys

#Unforunately, you can't split up positional arguments in a reasonable way if you
#don't know about all of them...  Count positional arguments (files)

def how_many_files(lst):
    return sum(1 for x in lst if not x.startswith('-'))

args = sys.argv[1:]
Nfiles = how_many_files(args)

import argparse

#Create our own NameSpace class so that we can have an easy handle on the
#attributes that the namespace actually holds.
class MyNameSpace(argparse.Namespace,dict):
    def __init__(self):
        argparse.Namespace.__init__(self)
        dict.__init__(self)

    def __setattr__(self,k,o):
        argparse.Namespace.__setattr__(self,k,o)
        self[k] = o

class MyParser(argparse.ArgumentParser):
    def __init__(self,*args,**kwargs):
        self.my_parents = kwargs.get('parents',[])
        argparse.ArgumentParser.__init__(self,*args,**kwargs)

class FooAction(argparse.Action):
    def __call__(self,parser,namespace,value,option_string=None):
        ref = namespace.pop('accumulated',{})
        try:
            del namespace.accumulated
        except AttributeError:
            pass

        #get a new namespace and populate it with the arguments we've picked up
        #along the way        
        new_namespace = self.__default_namespace(parser)
        for k,v in namespace.items():
            setattr(new_namespace,k,v)
            delattr(namespace,k)  #delete things from `namespace.__dict__`

        namespace.clear() #also remove things from the dictionary side.
        namespace.accumulated = ref
        new_namespace.file = value
        ref[value] = new_namespace

    def __default_namespace(self,parser):
        n = argparse.Namespace()
        for parent in parser.my_parents:
            parent.parse_args([],namespace=n)
        return n


parser = argparse.ArgumentParser()
parser.add_argument('-A',action='store_true')
parser.add_argument('-B',action='store_true')
parser.add_argument('-C',action='store_true')
parser.add_argument('-D',action='store_true')


parser2 = MyParser(parents=[parser],conflict_handler='resolve')
for i in range(Nfiles):
    parser2.add_argument('files%d'%i,action=FooAction,default=argparse.SUPPRESS)


n = parser2.parse_args(args,namespace = MyNameSpace())
for k,v in n.accumulated.items():
    print k,v

调用它:

~ $ python test.py -A foo bar -A -B -C qux

产量:

qux Namespace(A=True, B=True, C=True, D=False, file='qux')
foo Namespace(A=True, B=False, C=False, D=False, file='foo')
bar Namespace(A=False, B=False, C=False, D=False, file='bar')
于 2012-11-02T18:12:23.890 回答
1

像往常一样,这个问题似乎并不完全是需要的......对不起。这是我的工作结果(受 unutbu 答案的启发),它还允许带有参数的每个文件选项。

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-A', action = 'store_true')
parser.add_argument('-B', action = 'store_true')
args, unk = parser.parse_known_args()

file_parser = argparse.ArgumentParser()
file_parser.add_argument('-C', action = 'store_true')
file_parser.add_argument('-D', action = 'store_true')
file_parser.add_argument('-V', "--variable-list")
file_parser.add_argument('file')

fargs=[]
n=len(unk)
while True:
        i=0
        for i in  range(n): # finding longest fully parsable tail
            Parsed, unkf = file_parser.parse_known_args(unk[i:n])
            if not unkf: break
        if i==n: # did not found parsable tail
            file_parser.parse_args(unk[0:n]) # cause error 
        else:
            fargs.append(Parsed)
            n=i
        if (n<=0): break
fargs.reverse()

print args
for argl in fargs:
        print argl

调用它:

myscript.py -A -B -C -D file1 -C -V a,b,c file

产量:

Namespace(A=True, B=True)
Namespace(C=True, D=True, file='file1', variable_list=None)
Namespace(C=True, D=False, file='file2', variable_list='a,b,c')
于 2012-11-04T10:48:50.140 回答
0

action=append选项可能会有所帮助。这将使您可以多次指定一个选项,并且具有特定选项的所有参数都将存储在它们各自的列表中。

...这是一个例子,让我们称之为sample.py

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-c", "--cfilein", action="append")
    parser.add_argument("-d", "--dfilein", action="append")
    args = parser.parse_args()
    print args.cfilein
    print args.dfilein

Execute: ./sample.py -c f1 -d f2 -c f3 -d f4
Output:  ['f1', 'f3']
         ['f2', 'f4']

查看:http ://docs.python.org/2/library/argparse.html#action ...希望这会有所帮助...

于 2012-11-02T18:50:58.037 回答