python散装笔记——83: 解析命令行参数

liftword1周前 (03-05)技术文章2

大多数命令行工具依赖于程序执行时传递给程序的参数。这些程序不提示输入,而是期望设置数据或特定的标志(变成布尔值)。这使得用户和其他程序都能在 Python 文件启动时通过数据运行它。本节将解释和演示 Python 命令行参数的实现和使用。

1: argparse 中的 Hello world

下面的程序会向用户问好。它需要一个位置参数,即用户名,也可以告诉用户问候语。

import argparse

parser = argparse.ArgumentParser()

parser.add_argument('name', help='name of user')

parser.add_argument('-g', '--greeting',
                    default='Hello',
                    help='optional alternate greeting'
                   )

args = parser.parse_args()

print("{greeting}, {name}!".format(
  greeting=args.greeting,
  name=args.name)
     )

$ python hello.py --help
usage: hello.py [-h] [-g GREETING] name

positional arguments:
  name                    name of user
optional arguments:
  -h, --help              show this help message and exit
  -g GREETING, --greeting GREETING optional alternate greeting

$ python hello.py world
Hello, world!
$ python hello.py John -g Howdy
Howdy, John!

详情请阅读 argparse 文档。

2: 使用 argv 命令行参数

每当从命令行调用 Python 脚本时,用户可以提供额外的命令行参数,这些参数将传递给脚本。程序员可以通过系统变量 sys.argv 获取这些参数(argv 是大多数编程语言的传统名称,意思是 “参数向量”)。

按照惯例,sys.argv 列表中的第一个元素是 Python 脚本本身的名称,而其余元素则是用户在调用脚本时传递的标记。

# cli.py
import sys
print(sys.argv)

$ python3 cli.py
=> ['cli.py']

$ python3 cli.py fizz
=> ['cli.py', 'fizz']

$ python3 cli.py fizz buzz
=> ['cli.py', 'fizz', 'buzz']

下面是另一个如何使用 argv 的例子。我们首先去掉 sys.argv 的初始元素,因为它包含脚本的名称。然后,我们将其余参数合并成一句话,最后打印这句话,并在前面加上当前登录用户的名称(以便模拟聊天程序)。

import getpass
import sys

words = sys.argv[1:]
sentence = " ".join(words)
print("[%s] %s" % (getpass.getuser(), sentence))

在 “手动 ”解析大量非位置参数时,通常使用的算法是遍历 sys.argv 列表。一种方法是遍历该列表并弹出其中的每个元素:

# reverse and copy sys.argv
argv = reversed(sys.argv)
# extract the first element
arg = argv.pop()

# stop iterating when there's no more args to pop()
while len(argv) > 0:
  if arg in ('-f', '--foo'):
    print('seen foo!')
  elif arg in ('-b', '--bar'):
    print('seen bar!')
  elif arg in ('-a', '--with-arg'):
    arg = arg.pop()
    print('seen value: {}'.format(arg))
  # get the next value
  arg = argv.pop()

3: 使用 argparse 设置互斥参数

如果希望两个或多个参数互斥。可以使用函数
argparse.ArgumentParser.add_mutually_exclusive_group()
。在下面的示例中,foo 或 bar 可以存在,但不能同时存在。

import argparse

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()

group.add_argument("-f", "--foo")
group.add_argument("-b", "--bar")
args = parser.parse_args()
print("foo = ", args.foo)
print ("bar = ", args.bar)

如果尝试运行脚本,同时指定 --foo--bar 参数,脚本将发出以下抱怨信息。

error: argument -b/--bar: not allowed with argument -f/--foo

4: 使用 docopt 的基本示例

docopt 颠覆了命令行参数解析。你只需编写程序的用法字符串,而无需解析参数,docopt 会解析用法字符串,并用它提取命令行参数。

"""
Usage:
script_docopt.py [-a] [-b] 
Options:
-a Print all the things.
-b Get more bees into the path.
"""

from docopt import docopt

if __name__ == "__main__":
  args = docopt(__doc__)
  import pprint; pprint.pprint(args)

运行样本:

$ python script_docopt.py
Usage:
    script_docopt.py [-a] [-b] 
$ python script_docopt.py something
{'-a': False,
'-b': False,
'': 'something'}
$ python script_docopt.py something -a
{'-a': True,
'-b': False,
'': 'something'}
$ python script_docopt.py -b something -a
{'-a': True,
'-b': True,
'': 'something'}

5: 使用 argparse 自定义解析器错误信息

您可以根据脚本需要创建解析器错误信息。这是通过
argparse.ArgumentParser.error 函数
实现的。下面的示例显示了脚本在给出 --foo 而未给出 --bar 时向 stderr 打印用法和错误信息的情况。

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("-f", "--foo")
parser.add_argument("-b", "--bar")
args = parser.parse_args()
if args.foo and args.bar is None:
  parser.error("--foo requires --bar. You did not specify bar.")

print("foo =", args.foo)
print("bar =", args.bar)

假设脚本名为 sample.py,并运行 python sample.py --foo ds_in_fridge.

这个脚本会发出如下提示:

usage: sample.py [-h] [-f FOO] [-b BAR]
sample.py: error: --foo requires --bar. You did not specify bar.

6: 使用 argparse.add_argument_group() 对参数进行概念分组

当你创建 argparse ArgumentParser() 并使用'-h'运行程序时,你会收到一条自动使用信息,解释你可以使用哪些参数运行软件。默认情况下,位置参数和条件参数被分为两类,例如,下面是一个小脚本(example.py)和运行 python example.py -h 时的输出。

import argparse

parser = argparse.ArgumentParser(description='Simple example')
parser.add_argument('name', help='Who to greet', default='World')
parser.add_argument('--bar_this')
parser.add_argument('--bar_that')
parser.add_argument('--foo_this')
parser.add_argument('--foo_that')
args = parser.parse_args()

usage: example2.py [-h] [--bar_this BAR_THIS] [--bar_that BAR_THAT]
                        [--foo_this FOO_THIS] [--foo_that FOO_THAT]
                        name

Simple example

positional arguments:
  name                Who to greet

optional arguments:
  -h, --help          show this help message and exit
  --bar_this BAR_THIS
  --bar_that BAR_THAT
  --foo_this FOO_THIS
  --foo_that FOO_THAT

在某些情况下,你需要将参数分成更多的概念部分来帮助用户。例如,你可能希望将所有输入选项放在一组,而将所有输出格式化选项放在另一组。上面的示例可以调整为将 --foo_* 参数与 --bar_* 参数分开。

import argparse

parser = argparse.ArgumentParser(description='Simple example')

parser.add_argument('name', help='Who to greet', default='World')
# Create two argument groups
foo_group = parser.add_argument_group(title='Foo options')
bar_group = parser.add_argument_group(title='Bar options')
# Add arguments to those groups
foo_group.add_argument('--bar_this')
foo_group.add_argument('--bar_that')
bar_group.add_argument('--foo_this')
bar_group.add_argument('--foo_that')
args = parser.parse_args()

当运行 python example.py -h 时,会产生这样的输出:

usage: example.py [-h] [--bar_this BAR_THIS] [--bar_that BAR_THAT]
                        [--foo_this FOO_THIS] [--foo_that FOO_THAT]
                        name

Simple example

positional arguments:
  name                Who to greet

optional arguments:
  -h, --help          show this help message and exit

Foo options:
  --bar_this BAR_THIS
  --bar_that BAR_THAT

Bar options:
  --foo_this FOO_THIS
  --foo_that FOO_THAT

7: 使用 docopt 和 docopt_dispatch 的高级示例

docopt 一样,使用 [docopt_dispatch] 时,你要在入口点模块的 __doc__ 变量中制作你的 --help。在那里,你以 doc string 作为参数调用 dispatch,这样它就可以运行解析器了。

这样,你就不用手动处理参数(通常会导致高循环的 if/else 结构),而只需让调度给出你想如何处理参数集。

这就是 dispatch.on 装饰器的作用:您只需向它提供应触发函数的参数或参数序列,该函数就会以匹配值作为参数执行。

"""Run something in development or production mode.

Usage: run.py --development  
run.py --production  
run.py items add 
run.py items delete 

"""
from docopt_dispatch import dispatch

@dispatch.on('--development')
def development(host, port, **kwargs):
  print('in *development* mode')

@dispatch.on('--production')
def development(host, port, **kwargs):
  print('in *production* mode')

@dispatch.on('items', 'add')
def items_add(item, **kwargs):
  print('adding item...')

@dispatch.on('items', 'delete')
def items_delete(item, **kwargs):
  print('deleting item...')

if __name__ == '__main__':
  dispatch(__doc__)

相关文章

Python 命令行工具 python 的常用参数执行命令

作为 Python 的初学者,最不缺见的就是命令行工具 python 的执行命令了,每每遇到就可能去查资料帮助,同样,自己也会不时的需要某些执行命令来完成自己的需求,鉴于此我对 python 工具的执...

如何在 Python 中执行外部命令 ?

Python 是一种强大的编程语言,可以帮助自动执行许多任务,包括在 Linux 系统上运行命令。在本指南的最后,您将能够使用 Python 轻松有效地执行 Linux 命令。使用 os 模块os 模...

Python 中的一些命令行命令

虽然 Python 通常用于构建具有图形用户界面 (GUI) 的应用程序,但它也支持命令行交互。命令行界面 (CLI) 是一种基于文本的方法,用于与计算机的操作系统进行交互并运行程序。从命令行运行 P...

入门必学25个python常用命令

以下是 Python 入门必学的 25 个常用命令(函数、语句等):基础输入输出与数据类型print():用于输出数据到控制台,例如print("Hello, World!")。input():获取用...

Python 基础教程 九之cron定时执行python脚本

前言在Linux或Unix系统中,你可以使用cron任务来定时执行Python脚本。cron是一个基于时间的作业调度器,允许你安排命令或脚本在系统上自动执行。安装cron大多数Linux发行版默认安装...

Python 基础教程十之设置cron作业在bash sh文件中执行python脚本

简介在上一节中,我们介绍了使用cron作业定时执行python脚本。这一节我们介绍使用bash sh文件执行批量python脚本。先回顾一下cron内容:设置cron作业是一种在Linux系统中定时执...