ZetCode

Python argparse

最后修改于 2024 年 9 月 24 日

在本文中,我们将展示如何使用 argparse 模块解析 Python 中的命令行参数。

Python argparse

argparse 模块可以轻松编写用户友好的命令行界面。它从 sys.argv 解析定义的参数。

argparse 模块还会自动生成帮助和用法消息,并在用户向程序提供无效参数时发出错误。

argparse 是一个标准模块;我们无需安装它。

使用 ArgumentParser 创建解析器,并使用 add_argument 添加新参数。参数可以是可选的、必需的或位置参数。

可选参数

以下示例创建了一个简单的参数解析器。

optional_arg.py
#!/usr/bin/python

import argparse

# help flag provides flag help
# store_true actions stores argument as True

parser = argparse.ArgumentParser()
   
parser.add_argument('-o', '--output', action='store_true', 
    help="shows output")

args = parser.parse_args()

if args.output:
    print("This is some output")

该示例添加了一个具有两个选项的参数:一个短选项 -o 和一个长选项 --ouput。这些是可选参数。

import argparse

导入模块。

parser.add_argument('-o', '--output', action='store_true', 
    help="shows output")

使用 add_argument 添加一个参数。将 action 设置为 store_true 将在参数存在时将其存储为 True。help 选项提供参数帮助。

args = parser.parse_args()

使用 parse_args 解析参数。解析后的参数作为对象属性存在。在我们的例子中,将有一个 args.output 属性。

if args.output:
    print("This is some output")

如果参数存在,我们将显示一些输出。

$ optional_arg.py -o
This is some output
$ optional_arg.py --output
This is some output

我们使用 -o--output 运行程序。

$ optional_arg.py --help
usage: optional_arg.py [-h] [-o]

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

我们可以显示程序帮助。

必需参数

使用 required 选项将参数设置为必需参数。

required_arg.py
#!/usr/bin/python

import argparse

# required arg

parser = argparse.ArgumentParser()
   
parser.add_argument('--name', required=True)

args = parser.parse_args()

print(f'Hello {args.name}')

该示例必须指定 name 选项;否则会失败。

$ required_arg.py --name Peter
Hello Peter

$ required_arg.py
usage: required_arg.py [-h] --name NAME
required_arg.py: error: the following arguments are required: --name

位置参数

以下示例使用位置参数。它们是使用 add_argument 创建的。

positional_arg.py
#!/usr/bin/python

import argparse

# positional args

parser = argparse.ArgumentParser()
   
parser.add_argument('name')
parser.add_argument('age')

args = parser.parse_args()

print(f'{args.name} is {args.age} years old')

该示例需要两个位置参数:name 和 age。

parser.add_argument('name')
parser.add_argument('age')

位置参数的创建不带连字符前缀。

$ positional_arg.py Peter 23
Peter is 23 years old

dest 选项

add_argumentdest 选项为参数指定一个名称。如果未给出,则从选项中推断。

dest.py
#!/usr/bin/python

import argparse
import datetime

# dest gives a different name to a flag

parser = argparse.ArgumentParser()
   
parser.add_argument('-n', dest='now', action='store_true', help="shows now")

args = parser.parse_args()

# we can refer to the flag
# by a new name
if args.now:

    now = datetime.datetime.now()
    print(f"Now: {now}")

该程序为 -n 参数赋予了 now 名称。

$ ./dest.py -n
Now: 2022-08-20 09:42:32.195881

type 参数

type 参数确定参数的类型。

rand_int.py
#!/usr/bin/python

import argparse
import random

# type determines the type of the argument

parser = argparse.ArgumentParser()
   
parser.add_argument('-n', type=int, required=True, 
    help="define the number of random integers")
args = parser.parse_args()

n = args.n

for i in range(n):
    print(random.randint(-100, 100))

该程序显示 -100 到 100 之间的 n 个随机整数。

parser.add_argument('-n', type=int, required=True, 
    help="define the number of random integers")

-n 选项需要一个整数值,并且是必需的。

$ rand_int.py -n 3
92
-61
-61

default 选项

default 选项指定默认值,如果未给出该值。

power.py
#!/usr/bin/python

import argparse

# required defines a mandatory argument 
# default defines a default value if not specified

parser = argparse.ArgumentParser()

parser.add_argument('-b', type=int, required=True, help="defines the base value")
parser.add_argument('-e', type=int, default=2, help="defines the exponent value")
args = parser.parse_args()

val = 1

base = args.b
exp = args.e

for i in range(exp):
    val *= base

print(val)

该示例计算指数。指数值不是必需的;如果未给出,则默认为 2。

$ power.py -b 3
9
$ power.py -b 3 -e 3
27

metavar 选项

metavar 选项为错误和帮助输出中预期的值指定一个名称。

metavar.py
#!/usr/bin/python

import argparse

# metavar gives name to the expected value 
# in error and help outputs

parser = argparse.ArgumentParser()
   
parser.add_argument('-v', type=int, required=True, metavar='value', 
    help="computes cube for the given value")
args = parser.parse_args()

print(args)

val = args.v

print(val * val * val)

该示例将预期值命名为 value。默认名称是 V

$ metavar.py -h
usage: metavar.py [-h] -v value

optional arguments:
  -h, --help  show this help message and exit
  -v value    computes cube for the given value

给定的名称显示在帮助输出中。

append 操作

append 操作允许对重复的选项进行分组。

appending.py
#!/usr/bin/python

import argparse

# append action allows to group repeating
# options

parser = argparse.ArgumentParser()
   
parser.add_argument('-n', '--name', dest='names', action='append', 
    help="provides names to greet")

args = parser.parse_args()

names = args.names

for name in names:
    print(f'Hello {name}!')

该示例向使用 nname 选项指定的所有名称生成问候消息;它们可以重复多次。

$ appending.py -n Peter -n Lucy --name Jane
Hello Peter!
Hello Lucy!
Hello Jane!

nargs 选项

nargs 指定应消耗的命令行参数的数量。

charseq.py
#!/usr/bin/python

import argparse
import sys

# nargs sets the required number of argument values
# metavar gives name to argument values in error and help output

parser = argparse.ArgumentParser()
parser.add_argument('chars', type=str, nargs=2, metavar='c',
                    help='starting and ending character')

args = parser.parse_args()

try:
    v1 = ord(args.chars[0])
    v2 = ord(args.chars[1])

except TypeError as e:

    print('Error: arguments must be characters')
    parser.print_help()
    sys.exit(1)

if v1 > v2:
    print('first letter must precede the second in alphabet')
    parser.print_help()
    sys.exit(1)

该示例显示从字符一到字符二的字符序列。它需要两个参数。

parser.add_argument('chars', type=str, nargs=2, metavar='c',
    help='starting and ending character')

使用 nargs=2,我们指定我们期望两个参数。

$ charseq.py e k
e f g h i j k

该程序显示从 e 到 k 的字符序列。

可以使用 * 字符设置可变数量的参数。

var_args.py
#!/usr/bin/python

import argparse

# * nargs expects 0 or more arguments

parser = argparse.ArgumentParser()
parser.add_argument('num', type=int, nargs='*')
args = parser.parse_args()

print(f"The sum of values is {sum(args.num)}")

该示例计算值的总和;我们可以为程序指定可变数量的参数。

$ var_args.py 1 2 3 4 5
The sum of values is 15

choices 选项

choices 选项将参数限制在给定的列表中。

mytime.py
#!/usr/bin/python

import argparse
import datetime
import time

# choices limits argument values to the 
# given list

parser = argparse.ArgumentParser()

parser.add_argument('--now', dest='format', choices=['std', 'iso', 'unix', 'tz'],
                    help="shows datetime in given format")

args = parser.parse_args()
fmt = args.format

if fmt == 'std':
    print(datetime.date.today())
elif fmt == 'iso':
    print(datetime.datetime.now().isoformat())
elif fmt == 'unix':
    print(time.time())
elif fmt == 'tz':
    print(datetime.datetime.now(datetime.timezone.utc))

在示例中,now 选项可以接受以下值:stdisounixtz

$ ./mytime.py --now iso
2022-08-20T09:44:22.437880
$ ./mytime.py --now unix
1660981466.8261166

head 示例

以下示例模仿 Linux head 命令。它显示文件开头 n 行的文本。

words.txt
sky
top
forest
wood
lake
wood

对于示例,我们有这个小测试文件。

head.py
#!/usr/bin/python

import argparse
from pathlib import Path

# head command
# working with positional arguments

parser = argparse.ArgumentParser()
   
parser.add_argument('f', type=str, help='file name')
parser.add_argument('n', type=int, help='show n lines from the top')

args = parser.parse_args()

filename = args.f

lines = Path(filename).read_text().splitlines()

for line in lines[:args.n]:
    print(line) 

该示例有两个选项:f 用于文件名,-n 用于要显示的行数。

$ head.py words.txt 3
sky
top
forest

互斥选项

add_mutually_exclusive_group 创建一个互斥选项组。

以下程序列出正在运行的进程。它使用 psutil 库来列出进程,并使用 rich 库将数据以表格形式输出。

process.py
import psutil
import argparse
from datetime import datetime
from rich import box
from rich.console import Console
from rich.table import Table
from datetime import date


def parse_arguments():

    parser = argparse.ArgumentParser()
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument('-a', '--all', action='store_true',
                       help='show all processes')
    group.add_argument('-n', '--name', help='show info about process name')

    args = parser.parse_args()
    return args.all, args.name


def list_process(name):

    now = f'{date.today()}'
    table = Table(title=f'Process', box=box.MINIMAL,
                  caption=now, caption_justify='left')
    table.add_column('id', style='cyan')
    table.add_column('process name', style='grey69')
    table.add_column('username')
    table.add_column('create time', style='blue')
    table.add_column('memory', style='green')

    process_count = 0

    for p in psutil.process_iter():

        if name in p.name().lower():
            ctime = datetime.fromtimestamp(p.create_time())
            memory_percent = p.memory_percent()
            table.add_row(f'{p.pid}', p.name(), p.username(),
                          ctime.isoformat(), f'{memory_percent:.2f}')
            process_count += 1

    if process_count > 0:

        console = Console()
        console.print(table, justify='center')
    else:

        print('no such process found')


def list_all_processes():

    now = f'{date.today()}'
    table = Table(title='Processes', box=box.MINIMAL,
                  caption=now, caption_justify='left')
    table.add_column('id', style='cyan')
    table.add_column('process name', style='grey69')

    pnames = []
    for p in psutil.process_iter():
        
        pnames.append(p.name())
        table.add_row(f'[bold]{p.pid}', f'[bold]{p.name()}')

    console = Console()
    console.print(table, justify='center')

    print(len(pnames), 'processes')
    print(len(set(pnames)), 'apps')


all_f, name = parse_arguments()

if all_f:
    list_all_processes()
elif name:
    list_process(name)

该程序提供有关正在运行的进程的信息。根据提供的选项,它要么列出所有正在运行的进程,要么提供有关特定进程的更多信息。

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-a', '--all', action='store_true',
                    help='show all processes')
group.add_argument('-n', '--name', help='show info about process name')

-a-n 选项是互斥的;我们要么列出所有进程,要么只列出特定进程。

来源

Python argparse - 语言参考

在本文中,我们学习了 Python argparse 模块。

作者

我叫 Jan Bodnar,是一位热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直撰写编程文章。至今,我已撰写了 1,400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Python 教程