16.2 用argparse解析命令行

    通常,使用argparse包含以下4个步骤。

    1.创建ArgumentParser。这里,我们可以为你提供命令行接口的总体信息,包括描述、改变已显示选项、参数的格式和-h是否作为“帮助”选项。通常,我们只需要提供描述,其他的选项都有合理的默认值。

    2.定义命令行选项和参数。可以通过用ArgumentParser.add _ argument()方法函数添加参数来定义。

    3.通过解析sys.argv命令行创建用于描述选项、选项参数和总体命令行参数的命名空间对象。

    4.用创建好的命名空间对象配置应用程序和处理参数。有很多其他的方法可以优雅地处理这个过程,它包括解析配置文件和命令行参数。我们会介绍其中的一些设计。

    argparse的一个重要功能是它为我们提供了统一的选项和参数的接口。选项和参数的主要不同是它们可以出现的次数。选项是可选的,所以可以出现零次或多次。参数通常出现一次或多次。

    我们可以简单地通过下面的代码创建解析器。

    parser = argparse.ArgumentParser( description="Simulate Blackjack" )

    我们提供了描述,因为这个选项没有合适的默认值。下面是为应用程序定义命令行API的一些通用模式。

    • 简单的on-off选项:我们通常会将这种选项视为一个-v或者— verbose选项。
    • 带参数选项:这可能是-s ','或者- separator '|'选项。
    • 位置参数:当我们需要将输入文件和输出文件作为命令行参数时可以使用。
    • 所有其他参数:当我们有许多输入文件时可以使用。
    • —version:用于显示版本号和退出的特殊选项。
    • —help:这个选项会显示帮助和退出。这是默认行为,我们不需要对这个行为做任何实现。

    一旦定义了参数,就可以解析和使用它们。下面演示了我们是如何解析它们的。

    config= parser.parse_args()

    config对象是argparse.Namespace对象,这个类和types.SimpleNamespace类似。它本身包含许多属性,我们也可以很容易地将更多的属性添加到这个对象中。

    我们会逐一介绍这6种常用的参数。ArgumentParser类中有许多聪明成熟的选项可以使用。它们中的大多数已经超出了通常的命令行参数处理的简单准则。通常,我们应该避免使用一些使描述程序变得非常复杂的选项,例如 find。当选项变得很复杂时,我们可能已经不知不觉地在Python之上创建了领域特定语言。为什么不直接使用Python呢?

    16.2.1 简单的on/off选项

    我们会用单个字母的短名称来定义一个简单的on-off选项,也可以提供一个更长的名称,还应该提供一个显式的操作。如果忽略更长的名称或者更长的名称不适合作为Python的变量,我们可能会希望提供一个目标变量。

    parser.add_argument( '-v', '—verbose', action='store_true', default=False )

    这会定义命令行选项的长版本和短版本。如果用户输入了选项,它会将verbose选项设为True。如果用户没有提供选项,versbose选项默认为False。下面是该选项的一些常见变化。

    • 我们可能将action改为'store _ false'并将默认值设为True。
    • 有时候,我们可能会用None作为默认值,而不是True或者False。
    • 有时候,我们会使用'store _ const'作为action,并且包含一个额外的const=参数。这让我们可以保存除了简单的布尔值之外的其他值,例如日志级别或者其他对象。
    • 可能也会用'count'作为action,这样使得该选项可以重复并能够递增count的值。在这种情况下,默认值通常是0。

    如果我们使用日志记录器,可能会用类似下面的代码来定义调试选项。

    parser.add_argument( '—debug', action='store_const', const=logging.
    DEBUG, default=logging.INFO, dest="logging_level" )

    我们将action改为store const,这意味着常量将被保存并提供logging. DEBUG的某个特定常量。这意味着生成的选项对象可以直接为配置根日志记录器提供需要的值。然后,可以简单地将日志记录器配置为使用config.logging level,而不必再使用任何的匹配或者条件处理过程。

    16.2.2 带参数选项

    我们会定义一个长名称和可选短名称的带参选项。我们会定义一个用于保存参数提供的值的action。我们也可以提供一个类型转换,以便希望把字符串转换为float或者int值。

    parser.add_argument( "-b", "—bet", action="store", default="Flat",
    choices=["Flat", "Martingale", "OneThreeTwoSix"], dest='betting_rule')
    parser.add_argument( "-s", "—stake", action="store", default=50,
    type=int )

    第1个例子定了两个版本的命令行语法,包括长版本和短版本。当解析命令行参数值时,选项之后必须带有一个字符串值,并且它必须来自于可用的choices。目标名称——betting _ rule会接收选项的参数字符串。

    第2个例子也定义了两个版本的命令行语法,它包含了一个类型转换。当解析参数值时,这个语法会保存选项之后的整数。长名称——stake会成为解析器创建的选项对象的值。

    在某些情况下,会有一些和参数相关的值。在本例中,我们可以提供一个将空格分隔的多个值整合为一个列表的nargs="+"选项。

    16.2.3 位置参数

    我们用不带" - "装饰的名称来定义位置参数。对于固定数量位置参数的情况,我们会将它们添加进解析器中。

    parser.add_argument( "input_filename", action="store" )
    parser.add_argument( "output_filename", action="store" )

    当解析参数值时,这两个位置参数字符串会保存在最终的命名空间对象中。我们可以用config.input filenameconfig.output filename访问这些参数值。

    16.2.4 所有其他参数

    我们用不带有" - "装饰的名称来定义参数列表,并且用nargs=变量提供建议信息。如果包含一个或者多个参数值,我们指定nargs="+"。如果包含零个或者多个参数值,我们指定nargs="+"。如果参数是可选的,我们指定nargs="?"。这会将所有其他参数的值作为一个单独的序列保存在最后生成的命名空间对象中。

    parser.add_argument( "filenames", action="store", nargs="*", metavar="file…" )

    当文件名列表是可选的时,它通常意味着如果没有提供特别的文件名就会使用STDIN或者STDOUT

    如果我们指定了nargs=,那么生成的结果就是一个列表。如果我们指定nargs=1,那么生成的对象就是只包含一个元素的列表。如果我们忽略nargs,那么结果就是用户提供的单一值。

    创建一个列表(即使它只包含一个元素)会为我们提供很多方便,因为我们可能希望用下面的方式来处理参数。

    for filename in config.filenames:
      process( filename )

    在某些例子中,我们可能希望提供一些包含STDIN的输入文件。这种需求的通用作法是将-文件名作为参数。我们必须在应用程序中以类似下面的方式来处理这种需求。

    for filename in config.filenames:
      if filename == '-':
        process(sys.stdin)
      else:
        with open(filename) as input:
          process(input)

    这段代码试图处理多个文件名,有可能包括-来显示什么时候应该在文件列表中处理标准输入。我们可能会将with语句放在try:块中。

    16.2.5 —version的显示和退出

    由于显示版本号的选项经常被使用,因此我们可以用下面的快捷方式显示版本信息。

    parser.addargument( "-V", "—version", action="version", version=_version )

    这个例子假设在文件的某个地方我们定义了一个全局模块version= "3.3.2",这个特殊的action="version"的副作用是在显示了版本信息之后会退出程序。

    16.2.6 —help的显示和退出

    显示帮助的选项是argparse模块的默认功能。另外一种特殊情况允许我们通过-h—help的默认设置改变help选项。这需要两样东西。首先,我们必须创建一个add _ help=False的解析器。这会禁用内置的-h—help功能。这么做了之后,会添加一个action="help",指定我们想用的参数(例如,'-?')。这会显示帮助文本并且退出。