使用argparse输出调用函数

11 投票
3 回答
15817 浏览
提问于 2025-04-16 02:37

我现在的代码是这样的。它让我可以解析我程序脚本接收到的多个参数。有没有更接近“最佳实践”的其他方法呢?我只见过关于如何设置argparse的代码,但没有看到实际使用它输出的代码。

def useArguments():
    x = 0
    while x <= 5:
        if x == 0:                      
            if args.getweather != None:
                getWeather(args.getweather)
        if x == 1:
            if args.post != None:
                post(args.post)
        if x == 2:
            if args.custompost != None:
                custompost(args.custompost)
        if x == 3:
            if args.list != None:
                listAccounts(args.list)
        if x == 4:
            if args.add != None:
                addAccount(args.add[0])
        if x == 5:
            if args.edit != None:
                editAccount(args.edit[0])
        x = x + 1    


if __name__ == '__main__':

    updateConfig()

    parser = argparse.ArgumentParser(description='Post Yahoo weather to Twitter.', epilog="Report any bugs to example@email.com", prog='Program')

    parser.add_argument('-a', '--add', nargs=1, help='Add a new account. Use the desired account name as an argument.')
    parser.add_argument('-e', '--edit', nargs=1, choices=accountListSTR[:-1], help='Edit an account. Use the desired account name as an argument.')
    parser.add_argument('-g', '--getweather', nargs='*', choices=accountListSTR, help='Get weather and post here. Specify account(s) as argument. Use "all" for all accounts. If you specify multiple accounts, separate by a space NOT a comma.')
    parser.add_argument('-p', '--post', nargs='*', choices=accountListSTR, help='Post weather to Twitter. Specify account(s) as argument. Use "all" for all accounts. If you specify multiple accounts, separate by a space NOT a comma.')
    parser.add_argument('-c', '--custompost', nargs=2, help='Post a custom message. Specify an account then type the message. Make sure you use "" around the message. Use "all" for all accounts.')
    parser.add_argument('-l', '--list', action='store_const', const='all', help='List all accounts.')
    parser.add_argument('--version', action='version', version='%(prog)s 0.3.3')

    args = parser.parse_args()

    useArguments()

3 个回答

4

除了 --version 这个选项外,其他你提供的操作更适合被当作“子命令”来处理。

我对 argparse 的具体情况不太了解,因为我还没试过 Python 2.7,但你可以看看 svn 命令作为一个例子,下面是一些命令行的伪代码:

myprog [--version] <command> [<command opts>...]

这里的 <command> 是指:

add|edit|getweather|post|custompost|list

<command opts> 是特定于那个命令的选项。使用 optparse(它的功能类似),这意味着当你调用 parse_args 时,你的命令会被返回到 args 中,这样你就可以做类似这样的事情:

opts, args = parser.parse_args()
if opts.version:
    ...
else:
    getattr("do_" + args[0])(*args[1:])

我发现这种模式在调试时特别有用,因为我可以通过命令行访问内部函数,并传递各种参数进行测试。根据你自己的项目需要,调整命令处理程序的选择。

6

请查看这个链接:http://docs.python.org/library/argparse.html#sub-commands

处理子命令的一个特别有效的方法是结合使用 add_subparsers() 方法和 set_defaults() 的调用,这样每个子解析器就知道应该执行哪个 Python 函数。

简单来说:

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

weather_parser = subparsers.add_parser('get-weather')
weather_parser.add_argument('--bar')
weather_parser.set_defaults(function=get_weather)  # !

args = parser.parse_args(['get-weather', '--bar', 'quux'])
print args.function(args)

在这里,我们为命令 get-weather 创建了一个子解析器,并将函数 get_weather 分配给它。

需要注意的是,文档中提到的关键字/属性叫 func,但实际上从 argparse 1.1 开始,它应该是 function

生成的代码有点啰嗦,所以我发布了一个小工具包 "argh",可以让事情变得更简单,比如:

parser = argparse.ArgumentParser()
add_commands(parser, [get_weather])
print dispatch(parser, ['get-weather', '--bar', 'quux'])

"Argh" 能做更多的事情,但我就不在这里多说了,让 Stack Overflow 来解答吧。:-)

11

你可以为一个参数提供自定义的动作,具体方法是:

传递一个实现了动作API的对象。最简单的方式是扩展 argparse.Action,并提供一个合适的 __call__ 方法。这个 __call__ 方法需要接受四个参数:

  1. parser:包含这个动作的 ArgumentParser 对象。
  2. namespace:将由 parse_args() 返回的命名空间对象。大多数动作会在这个对象上添加一个属性。
  3. values:与命令行参数相关的值,已经应用了任何类型转换。(类型转换是通过 add_argument() 的 type 关键字参数指定的。)
  4. option_string:用于调用这个动作的选项字符串。这个 option_string 参数是可选的,如果这个动作与位置参数关联,则不会出现。

撰写回答