argparse on demand imports for types, choices etc

后端 未结 4 1320
一整个雨季
一整个雨季 2021-01-20 11:10

I have quite a big program which has a CLI interaction based on argparse, with several sub parsers. The list of supported choices for the subparsers arguments a

4条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2021-01-20 11:36

    This is a script that tests the idea of delaying the creation of a subparser until it is actually needed. In theory it might save start up time, by only creating the subparser that's actually needed.

    I use the nargs=argparse.PARSER to replicate the subparser behavior in the main parser. help behavior is similar.

    # lazy subparsers test
    # lazy behaves much like a regular subparser case, but only creates one subparser
    # for N=5 time differences do not rise above the noise
    
    import argparse
    
    def regular(N):
        parser = argparse.ArgumentParser()
        sp = parser.add_subparsers(dest='cmd')
        for i in range(N):
            spp = sp.add_parser('cmd%s'%i)
            spp.set_defaults(func='cmd%s'%(10*i))
            spp.add_argument('-f','--foo')
            spp.add_argument('pos', nargs='*')
        return parser
    
    def lazy(N):
        parser = argparse.ArgumentParser()
        sp = parser.add_argument('cmd', nargs=argparse.PARSER, choices=[])
        for i in range(N):
            sp.choices.append('cmd%s'%i)
        return parser
    
    def subpar(cmd):
        cmd, argv = cmd[0], cmd[1:]
        parser = argparse.ArgumentParser(prog=cmd)
        parser.add_argument('-f','--foo')
        parser.add_argument('pos', nargs='*')
        parser.set_defaults(func=cmd)
        args = parser.parse_args(argv)
        return args
    
    N = 5
    mode = True #False
    argv = 'cmd1 -f1 a b c'.split()
    if mode:
        args = regular(N).parse_args(argv)
        print(args)
    else:
        args = lazy(N).parse_args(argv)
        print(args)
        if isinstance(args.cmd, list):
            sargs = subpar(args.cmd)
            print(sargs)
    

    test runs with different values of mode (and N=5)

    1004:~/mypy$ time python3 stack44315696.py 
    Namespace(cmd='cmd1', foo='1', func='cmd10', pos=['a', 'b', 'c'])
    
    real    0m0.052s
    user    0m0.044s
    sys 0m0.008s
    1011:~/mypy$ time python3 stack44315696.py 
    Namespace(cmd=['cmd1', '-f1', 'a', 'b', 'c'])
    Namespace(foo='1', func='cmd1', pos=['a', 'b', 'c'])
    
    real    0m0.051s
    user    0m0.048s
    sys 0m0.000s
    

    N has to be much larger to start seeing a effect.

提交回复
热议问题