argparsemain parser和sub-parsers

Posted 不吃饭就会放大招

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了argparsemain parser和sub-parsers相关的知识,希望对你有一定的参考价值。

在 Python 的 argparse 模块中,可以创建一个主解析器/父解析器(main parser)和多个子解析器(sub-parsers)。其中,main parser 中定义作用于整个项目的解析器,sub-parsers 中定义特定于某一些功能的子解析器。其中:

  • main parser 中的选项称作 global option,这些全局选项作用于整个项目
  • sub-parsers 中的选项称作 sub option,子选项的作用范围限制在子解析器内

通过使用一个主解析器和多个子解析器,能够创建更加灵活的命令行接口。

使用示例

下面的示例代码中,定义了一个主解析器 parser 和两个子解析器 parser_aparser_b

import argparse

# Set up the main parser
parser = argparse.ArgumentParser(description='A program with sub-commands')  # 1
parser.add_argument('--verbose', action='store_true', help='increase output verbosity')  # 2

# Set up subparsers for the different sub-commands
subparsers = parser.add_subparsers(title='sub-commands', dest='subcommand', description='valid subcommands', help='additional help')  # 3

# Add subparsers for each sub-command
parser_a = subparsers.add_parser('command_a', help='description of command_a')  # 4
parser_a.add_argument('--option_a', type=int, help='description of option_a')  # 5
parser_b = subparsers.add_parser('command_b', help='description of command_b')  # 6
parser_b.add_argument('--option_b', type=float, help='description of option_b')  # 7
# Add subparsers for additional sub-commands here

# Parse the command-line arguments
args = parser.parse_args()  # 8

if args.verbose:
    print('Verbose mode enabled')

# Check which sub-command was specified and handle its options
if args.subcommand == 'command_a':  # 9
    if args.option_a:
        print(f'command_a was run with option_a=args.option_a')
    else:
        print('command_a was run')
elif args.subcommand == 'command_b':
    if args.option_b:
        print(f'command_b was run with option_b=args.option_b')
    else:
        print('command_b was run')
  • 1 处,通过 argparse.ArgumentParser() 定义主解析器 parser
  • 2 处,通过 .add_argument() 方法为主解析器添加一个全局选项:–verbose
  • 3 处,通过 .add_subparsers() 方法创建子解析器 subparsers,作为主解析器 parser 的子解析器,每个 subparser 都通过不同的子命令行指示(参数 dest
  • 46 处,通过 subparsers.add_parser() 创建了两个子解析器 parser_aparser_b
  • 57 处,通过 add_argument() 为子解析器分别添加子选项 –option_a–option_b
  • 8 处,使用 parser.parse_args() 对命令行参数进行解析
  • 9 处,args.subcommand3 处的参数 dest,通过子解析器的名称进行判断

命令行执行程序:

$ python my_tool.py command_a --option_a 42

args.subcommand 指定了当前使用哪个子解析器,上面的例子中,command_a 指定子解析器为 parser_a,同时指定了解析器 parser_a 的选项 –option_a。输出:

command_a was run with option_a=42

在命令行同时使用 –verbose–option_a

$ python my_tool.py --verbose command_a --option_a 42

此时程序开启 verbose 模式,同时执行子解析器 parser_a,输出:

Verbose mode enabled
command_a was run with option_a=42

使用“import dateutil”和“dateutil.parser.parse()”时出现AttributeError,但使用“from dateutil import parser”时没有问题

【中文标题】使用“import dateutil”和“dateutil.parser.parse()”时出现AttributeError,但使用“from dateutil import parser”时没有问题【英文标题】:AttributeError when using "import dateutil" and "dateutil.parser.parse()" but no problems when using "from dateutil import parser" 【发布时间】:2014-06-16 14:12:03 【问题描述】:

我在 Python 2.7.3 中使用 dateutil module。我只是想使用:

import dateutil
dateutil.parser.parse("01-02-2013")

但是我得到了一个错误:

AttributeError: 'module' object has no attribute 'parser'

我检查了dateutil 有哪些属性

print dir(dateutil)
# output: ['__author__', '__builtins__', '__doc__', '__file__', '__license__',
#          '__name__', '__package__', '__path__', '__version__']

问题是,当我尝试直接从dateutil 导入parser 时,它似乎确实存在:

from dateutil import parser
print parser.parse("01-02-2013")
# output: 2013-01-02 00:00:00

from dateutil import parser之后,parser也神奇地出现在了导入的dateutil本身中:

print dir(dateutil)
# output: ['__author__', '__builtins__', '__doc__', '__file__', '__license__',
#          '__name__', '__package__', '__path__', '__version__', 'parser',
#          'relativedelta', 'tz']

请注意,此列表中仍然缺少一些其他属性(例如 rrule)。

有人知道怎么回事吗?

【问题讨论】:

【参考方案1】:

您尚未导入dateutil.parser。您可以看到它,但您必须以某种方式导入它。

>>> import dateutil.parser
>>> dateutil.parser.parse("01-02-2013")
datetime.datetime(2013, 1, 2, 0, 0)

这是因为parser.pydateutil 包中的一个模块。它是文件夹结构中的一个单独文件。

回答你在 cmets 中提出的问题,relativedeltatz 在你 from dateutil import parser 之后出现在命名空间中的原因是因为 parser 本身导入了 relativedeltatz

如果你查看dateutil/parser.py 的源代码,你可以看到导入。

# -*- coding:iso-8859-1 -*-
"""
Copyright (c) 2003-2007  Gustavo Niemeyer <gustavo@niemeyer.net>

This module offers extensions to the standard Python
datetime module.
"""
... snip ...
from . import relativedelta
from . import tz

【讨论】:

我认为您可以像导入任何其他模块一样导入它。例如,如果我想使用datetime.date.today(),我会先使用import datetime,然后再使用print datetime.date.today()。这对dateutil 不起作用有什么原因吗? 我明白了。那么dateutil 中的所有其他属性(如rrule)都是单独的文件,因此您总是必须使用import dateutil.[attribute_name] 来使用它们? 不一样,datedatetime.py文件中的一个类,而dateutil.parser实际上是一个单独的文件,parser.py在dateutil包中。 @Neftas 是的,差不多就是这样。 谢谢!关于为什么在from dateutil import parser 之后,第二个print dir(dateutil) 突然显示relativedeltatz 有什么想法吗?

以上是关于argparsemain parser和sub-parsers的主要内容,如果未能解决你的问题,请参考以下文章

XML Pull Parser 和 SAX Parser 有啥区别

使用“import dateutil”和“dateutil.parser.parse()”时出现AttributeError,但使用“from dateutil import parser”时没有问题

dateutil.parser.parse() 和丢失的时区信息

转babel-parser和acorn的区别

Angular 1.5 组件 + ng-model $formatters 和 $parsers

$parsers & $formatters