如何在 Python 中解析命令行参数

想知道如何在执行 Python 脚本时运用命令行参数吗?本文将深入探讨如何利用 Python 的 sysgetoptargparse 模块来解析这些参数。

在 Python 中,通常使用 input() 函数来接收用户的输入。但是,在某些情境下,你可能需要在通过命令行执行脚本时传递一些特定的参数。

本文将指引你如何在命令行中使用选项和参数来运行 Python 脚本,并展示如何利用 Python 内置的模块来解析这些选项和参数。

让我们开始吧!

理解 Python 中的 sys.argv

如果你熟悉 C 语言编程,你一定知道通过命令行向程序传递参数是一种常见方法。在 C 语言中,通常会这样定义 main 函数:

#include<stdio.h>

int main(int argc, char **argv){
    //argc: argument count
    //argv: argument vector

    //do something on the args

    return 0;
}

这里,argc 代表参数的个数,argv 则代表参数向量。

使用命令行参数运行 Python 脚本

在 Python 中,你可以通过 python3 filename.py 在命令行中运行 Python 脚本。 你还可以在执行脚本时传入任意数量的命令行参数:

$ python3 filename.py arg1 arg2 ... argn

sys 模块为我们提供了直接访问和处理这些命令行参数的支持。sys.argv 是一个列表,其中包含了我们在运行 Python 脚本时传入的所有命令行参数。

下面是一个使用命令行参数运行 main.py 的示例:

$ python3 main.py hello world python script

我们可以通过简单的 for 循环和 enumerate 函数来遍历这个参数向量:

# main.py

import sys

for idx, arg in enumerate(sys.argv):
    print(f"arg{idx}: {arg}")
# 输出
arg0:main.py
arg1:hello
arg2:world
arg3:python
arg4:script

可以看到,第一个参数(索引为 0)是 Python 文件的名称,后续的参数从索引 1 开始。

这是一个接收并处理命令行参数的最小程序。 但是,我们发现了一些问题:

  • 用户如何知道需要传递哪些参数?
  • 这些参数代表什么?

这些问题都不是很明确。 为了解决这些问题,你可以使用 getoptargparse 模块,我们将在接下来的部分学习如何使用它们。✅

使用 Python 的 getopt 解析命令行参数

现在,让我们来学习如何使用内置的 getopt 模块来解析命令行参数。

导入 getopt 模块后,你可以定义需要解析的参数以及脚本支持的短选项和长选项。 我们需要解析 sys.argv 中从索引 1 开始的所有参数,所以需要解析的切片是 sys.argv[1:]

假设我们需要一个消息字符串和一个文件名。 我们可以使用 mf 作为短选项,messagefile 作为长选项。

那么如何确保某些选项需要参数呢?

  • 对于短选项,可以在短选项名称后添加冒号 (:) 来使其需要参数。
  • 对于长选项,可以在长选项名称后添加等号 (=) 来使其需要参数。

结合以上定义,我们在 main.py 中会有以下代码:

# main.py

import sys
from getopt import getopt

opts, args = getopt(sys.argv[1:],'m:f:',['message=','file='])

print(opts)
print(args)

在这里,变量 opts 包含选项和参数,以元组列表的形式存储。 任何其他的参数(位置参数)都会被收集到 args 变量中。

我们可以通过短选项或长选项传入消息和文件名来运行脚本。

使用长选项运行 main.py,我们得到:

$ python3 main.py --message hello --file somefile.txt

选项和参数作为元组存储在 opts 变量中。 由于我们没有传递任何位置参数,args 是一个空列表。

# 输出
[('--message', 'hello'), ('--file', 'somefile.txt')]
[]

同样,我们也可以使用短选项,如下所示:

$ python3 main.py -m hello -f somefile.txt
# 输出
[('-m', 'hello'), ('-f', 'somefile.txt')]
[]

⚠️ 请注意,本例中的短选项 -m 不要与命令行标志 -m 混淆,命令行标志 -m 用于在运行 Python 脚本时将模块作为主模块运行。

例如,在运行 main.py 时,你会使用 python3 -m unittest main.pyunittest 作为主模块运行。

前面提到,所有其它的位置参数都会被收集到 args 变量中。 下面是一个例子:

$ python3 main.py -m hello -f somefile.txt another_argument

args 列表包含了位置参数 another_argument

# 输出
[('-m', 'hello'), ('-f', 'somefile.txt')]
['another_argument']

在这里,opts 是一个元组列表,我们可以遍历它,解包元组,并提取与特定选项对应的参数。

处理完这些参数后,我们应该如何处理文件名和消息呢? 我们可以以写入模式打开文件,并将转换为大写的消息字符串写入文件。

# main.py
import sys
from getopt import getopt

opts, args = getopt(sys.argv[1:],'m:f:',['message=','file='])

print(opts)
print(args)

for option, argument in opts:
    if option == "-m":
        message = argument
    if option == '-f':
        file = argument

with open(file,'w') as f:
    f.write(message.upper())

让我们使用短选项和命令行参数来运行 main.py

$ python main.py -m hello -f thisfile.txt
[('-m', 'hello'), ('-f', 'thisfile.txt')]
[]

运行 main.py 后,我们可以在工作目录中看到名为 thisfile.txt 的文件。 该文件包含了被转换为大写的字符串 ‘hello’ (‘HELLO’)。

$ ls
main.py  thisfile.txt
$ cat thisfile.txt
HELLO

如何使用 argparse 解析命令行参数

argparse 模块也是 Python 标准库的一部分,它提供了解析命令行参数和构建命令行接口的功能。

为了解析命令行参数,我们需要从 argparse 模块导入 ArgumentParser 类。 然后,我们实例化 arg_parser,即一个 ArgumentParser 对象:

from argparse import ArgumentParser

arg_parser = ArgumentParser()

接下来,我们要添加两个命令行参数:

  • message:消息字符串;
  • file:我们想要使用的文件的名称。

现在,我们可以调用 arg_parseradd_argument() 方法来添加这两个参数。 在 add_argument() 方法调用中,你可以通过 help 字段设置参数的描述。

arg_parser.add_argument('message',help='消息字符串')
arg_parser.add_argument('file',help='文件名')

到目前为止,我们已经实例化了 arg_parser 并添加了命令行参数。 当程序在命令行运行时,你可以使用 arg_parserparse_args() 方法来获取参数的值。

在这里,我们将参数命名空间捕获到变量 args 中。 所以你可以通过 args.argument_name 来获取参数的值。

获取参数值后,我们将消息字符串(使用 swapcase() 字符串方法)进行大小写转换,并写入文件。

args = arg_parser.parse_args()

message = args.message
file = args.file

with open(file,'w') as f:
     f.write(message.swapcase())

综合以上步骤,我们的 main.py 文件如下:

# main.py

from argparse import ArgumentParser

arg_parser = ArgumentParser()
arg_parser.add_argument('message',help='消息字符串')
arg_parser.add_argument('file',help='文件名')

args = arg_parser.parse_args()
print(args)

message = args.message
file = args.file

with open(file,'w') as f:
     f.write(message.swapcase())

了解命令行参数用法

为了解 main.py 的参数使用方法,你可以使用 --help 长选项,如下所示:

$ python3 main.py --help
usage: main.py [-h] message file

positional arguments:
  message     消息字符串
  file        文件名

optional arguments:
  -h, --help  显示此帮助信息并退出

这里没有可选参数,messagefile 都是必需的位置参数。 你也可以使用短选项 -h

$ python3 main.py -h
usage: main.py [-h] message file

positional arguments:
  message     消息字符串
  file        文件名

optional arguments:
  -h, --help  显示此帮助信息并退出

如上所示,默认情况下这两个参数都是位置参数。 因此,如果你没有传递其中一个或多个参数,就会出错。

在以下示例中,我们为消息字符串传递了一个位置参数 (Hello),但没有为文件参数提供值。

结果,我们收到一个错误消息,提示需要文件参数。

$ python3 main.py Hello
usage: main.py [-h] message file
main.py: error: the following arguments are required: file

当使用两个位置参数运行 main.py 时,我们可以看到命名空间 args 中包含了参数的值。

$ python3 main.py Hello file1.txt
# 输出
Namespace(file="file1.txt", message="Hello")

现在,如果检查当前工作目录的内容,我们会看到脚本创建了一个文件 file1.txt

$ ls
file1.txt  main.py

原始的消息字符串是 ’Hello’; 在进行大小写转换后,file1.txt 文件中的消息字符串变为 “hELLO”。

$ cat file1.txt
hELLO

如何使命令行参数可选

要使命令行参数可选,可以在参数名称前加上 --

现在,我们修改 main.py,使消息和文件参数都是可选的。

# main.py

from argparse import ArgumentParser

arg_parser = ArgumentParser()
arg_parser.add_argument('--message',help='消息字符串')
arg_parser.add_argument('--file',help='文件名')

由于命令行参数都是可选的,我们可以为这些参数设置默认值。

if args.message and args.file:
    message = args.message
    file = args.file
else:
    message="Python3"
    file="myfile.txt"

此时,main.py 文件包含以下代码:

# main.py

from argparse import ArgumentParser

arg_parser = ArgumentParser()
arg_parser.add_argument('--message',help='消息字符串')
arg_parser.add_argument('--file',help='文件名')

args = arg_parser.parse_args()
print(args)

if args.message and args.file:
    message = args.message
    file = args.file
else:
    message="Python3"
    file="myfile.txt"

with open(file,'w') as f:
     f.write(message.swapcase())

如果检查用法,我们可以看到 messagefile 都是可选参数。 这意味着你现在可以在没有这两个参数的情况下运行 main.py

$ python3 main.py --help
usage: main.py [-h] [--message MESSAGE] [--file FILE]

optional arguments:
  -h, --help         显示此帮助信息并退出
  --message MESSAGE  消息字符串
  --file FILE        文件名
$ python3 main.py

在参数命名空间中,filemessage 都是 None

# 输出
Namespace(file=None, message=None)

我们看到程序使用了默认文件名和消息 myfile.txtPython3。 文件 myfile.txt 现在位于工作目录中:

$ ls
file1.txt  main.py  myfile.txt

它包含了经过大小写转换后的字符串 Python3

$ cat myfile.txt
pYTHON3

你也可以同时使用 --message--file 参数来使命令更易读。

$ python3 main.py --message Coding --file file2.txt
# 输出
Namespace(file="file2.txt", message="Coding")

我们在工作目录中看到了 file2.txt

$ ls
file1.txt  file2.txt  main.py  myfile.txt

并且该文件包含了预期的字符串 ‘cODING’。

$ cat file2.txt
cODING

结论

以下是对本文所学内容的总结:

  • 与 C 语言类似,在 Python 中,你可以通过遍历参数向量 sys.argv 来访问命令行参数。 sys.argv[0] 是 Python 脚本的名称。所以我们需要解析的参数是 sys.argv[1:]
  • 但是,为了提高代码的可读性并添加选项,可以使用 getoptargparse 模块。
  • 你可以使用 getopt 模块来解析从索引 1 到列表末尾的命令行参数列表。 你可以定义短选项和长选项。
  • 当选项需要参数时,你可以在短选项后添加冒号 (:),在长选项后添加等号 (=)。
  • 使用 Python 的 argparse 模块,你可以实例化一个 ArgumentParser 对象,并使用 add_argument() 方法添加所需的位置参数。在参数名称前加上 -- 可以使其成为可选参数。
  • 要检索命令行参数的值,请在 ArgumentParser 对象上调用 parse_args() 方法。

接下来,学习如何在 Python 中执行安全哈希。