全文一览
一、前言
1.1 需求分析
很多时候我们为了解决某一特定的问题,要对代码做定制化,这就导致代码难以被直接复用,当我们将代码用于不同的场景时,需要进入代码内部修改(比如修改文件所在的路径)。
这样频繁地修改代码显然不够 Pythonic,有没有更好的解决办法呢?
1.2 解决思路
既然 Python 中通过函数传参,能够增加函数的复用性;能不能给文件传参(对 main 函数传参)增加文件的复用性呢?
参考函数传参的方法,我们可以进行位置传参和关键字传参两种方式传递参数,命令行默认通过位置进行传参,可以使用 sys.argv 查看参数列表;而要实现后者,Python 中内置的 argparse 库或许能帮上忙!
二、命令行传参
2.1 命令行传参机制
首先,创建一个文件(如 arguments.py),写入如下代码:
import sys
if __name__ == "__main__":
print("sys.argv:", sys.argv)
打开终端,跳转到该文件所在路径(如 D:\PycharmProjects\Carl\Args),键入命令行 “python arguments.py aaa 123 xyz”,即可显示本条命令行传入的参数:
可见传入的参数是一个列表,列表中的元素都默认是以字符串的形式传入的。其中共有四个单词,没有命令 “python”,第一个元素是函数名(即所执行的文件):
sys.argv: ['arguments.py', 'aaa', '123', 'xyz']
参数列表的第一个元素永远是当前命令所执行文件的路径!
2.2 如何用命令行传参
通过上面的知识,我们可以通过 sys.argv 获取对应的参数,我们可以通过 sys.argv 获取对应的参数,并实现对数组求和:
import sys
if __name__ == '__main__':
res = 0
for i in range(1, len(sys.argv)):
res += int(sys.argv[i])
print("sum:", res)
输入不同长度的数列,分别可以计算它们的和:
此外,我们可以通过 sys.argv 获取对应的参数,并实现两个数的减法:
import sys
if __name__ == "__main__":
a = int(sys.argv[1])
b = int(sys.argv[2])
print("sub:", a - b)
如下图,这种方式确实可以实现传入两个参数打印二者的差值:
--当传输的数字顺序不同,差值也会不同;
--当传入的数字超过两个时,只截取前面两个参数;
--当传入的数字不足两个时,则会报错!
命令行默认的传参方式对位置和数量非常依赖,需要预知传参的数量及其位置对应!
这种传参方式未免太过严格!
能不能打乱顺序(如先输入减数,再输入被减数)进行输入呢?
当参数缺失时(如未输入减数)能不能将其默认为一个值(比如 0)呢?
这正是 argparse 要解决的问题!
三、argparse 传参
argparse 可以实现通过关键字传入参,需要先构建解析器(parser)的结构,再对命令行解析获得相应的参数。
3.1 基本用法
首先,要实例化 ArgumentParser 类,构建解析器 parser:
import argparse
# 构建参数解释器,用于解析命令行参数
parser = argparse.ArgumentParser()
之后可以添加关键字 a、b,必须以 ‘-’ 或 ‘–’ 开头:
# 添加参数 a、b
parser.add_argument('-a')
parser.add_argument('--b')
对参数进行解析,结果保留在 args 变量中。通过 ‘.’ 加关键字,即可实现对参数的访问:
# 解析参数
args = parser.parse_args()
print("args:", args)
print("type(args):", type(args)) # <class 'argparse.Namespace'>
# 查看参数
print("args.a:", args.a)
print("args.b:", args.b)
在命令行输入“python arguments.py -a 5 --b 6”,发现确实可以捕获到参数 a 和 b ,而且二者是可以交换位置的!
此时的参数仍然是 ‘str’ 格式的,如何将其设置为整形或者其他类型?
不传入该参数时会因找不到而报错,如何为其设置一个默认的值?
3.2 进阶使用
如下,我们可以在 add_argument 函数内部,通过 type 设置参数类型为 int、float 等,通过 default 设置默认值,通过 choices 设置参数范围,通过 help 设置帮助信息:
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser("此解释器仅用于示范!")
parser.add_argument('-a', '--Apple', type=int, default=3, help='请在该参数后面加上苹果的数量,否则默认为三个!')
parser.add_argument('-b', '--Banana', type=int, help='请在该参数后面加上香蕉的数量!')
parser.add_argument('--Cherry', type=int, choices=range(10, 21), help="请在该参数后面加上樱桃的数量,注意不少于10,不大于20!")
parser.add_argument('-m', type=float, default=99.9, help="请在该参数后面加上总花了多少钱!")
args = parser.parse_args()
print(f"您这次共买了{args.Apple}个苹果,{args.Banana}根香蕉,以及{args.Cherry}颗樱桃,累计消费{args.m}元!")
注意:当 ‘-a’ 和 ‘–Apple’ 同时存在于一个参数内部时,可以用 args.Apple 获取参数,但不能再通过 args.a 获取!
我们输入参数进行试验:
由上图可见,能够实现参数位置的改变;可以通过大写全称、小写简称传入参数;有默认值的参数还可以省略;而且还可以使用 ‘=’ 填充参数名和实际值之间的空格(注意这里只有一个等号,两个等号则不行)。
3.3 查看帮助信息
我们还可以通过 “ python arguments.py -h” 或 “python arguments.py --help” 来查看此文档的帮助信息:
3.4 两个整数相减
回到第二章的问题,可以通过 argparse 实现两个整数求差:
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-a', type=int, default=0)
parser.add_argument('-b', type=int, default=0)
args = parser.parse_args()
print('a-b:', args.a - args.b)
第二章的功能得以实现:
四、完整代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @FileName : arguments.py
# @Time : 2024/1/17 21:39
# @Author : Carl.Zhang<18810013585@163.com,https://github.com/Carl-Zfg>
# Function : arguments
# # 2.1 命令行传参机制
# import sys
#
# if __name__ == "__main__":
# print("sys.argv:", sys.argv)
# # 2.2 如何用命令行传参:打印序列和
# import sys
#
# if __name__ == '__main__':
# res = 0
# for i in range(1, len(sys.argv)):
# res += int(sys.argv[i])
# print("sum:", res)
# # 2.2 如何用命令行传参:两个数相减
# import sys
#
# if __name__ == "__main__":
# a = int(sys.argv[1])
# b = int(sys.argv[2])
# print("sub:", a - b)
# # 3.1 基本用法
# import argparse
#
# # 构建参数解释器,用于解析命令行参数
# parser = argparse.ArgumentParser()
# # 添加参数 a、b
# parser.add_argument('-a')
# parser.add_argument('--b')
# # 解析参数
# args = parser.parse_args()
# print("args:", args)
# print("type(args):", type(args)) # <class 'argparse.Namespace'>
# # 查看参数
# print("args.a:", args.a)
# print("args.b:", args.b)
# print("type(args.a)", type(args.a))
# # 3.2 进阶使用
# import argparse
#
# if __name__ == '__main__':
# parser = argparse.ArgumentParser("此解释器仅用于示范!")
# parser.add_argument('-a', '--Apple', type=int, default=3, help='请在该参数后面加上苹果的数量,否则默认为三个!')
# # 注意:当 ‘-’ 和 ‘--’ 同时存在时,可以用 args.Apple 获取参数,但不能再通过 args.a 获取
# parser.add_argument('-b', '--Banana', type=int, help='请在该参数后面加上香蕉的数量!')
# parser.add_argument('--Cherry', type=int, choices=range(10, 21), help="请在该参数后面加上樱桃的数量,注意不少于10,不大于20!")
# parser.add_argument('-m', type=float, default=99.9, help="请在该参数后面加上总花了多少钱!")
#
# args = parser.parse_args()
# print(f"您这次共买了{args.Apple}个苹果,{args.Banana}根香蕉,以及{args.Cherry}颗樱桃,累计消费{args.m}元!")
# # 3.4 两个整数相减
# import argparse
#
# if __name__ == '__main__':
# parser = argparse.ArgumentParser()
# parser.add_argument('-a', type=int, default=0)
# parser.add_argument('-b', type=int, default=0)
# args = parser.parse_args()
# print('a-b:', args.a - args.b)
# 对3.2进行封装
import argparse
# 构建解析器
def get_parser():
parser = argparse.ArgumentParser("此解释器仅用于示范!")
parser.add_argument('-a', '--Apple', type=int, default=3, help='请在该参数后面加上苹果的数量,否则默认为三个!')
# 注意:当 ‘-’ 和 ‘--’ 同时存在时,可以用 args.Apple 获取参数,但不能再通过 args.a 获取
parser.add_argument('-b', '--Banana', type=int, help='请在该参数后面加上香蕉的数量!')
parser.add_argument('--Cherry', type=int, choices=range(10, 21), help="请在该参数后面加上樱桃的数量,注意不少于10,不大于20!")
parser.add_argument('-m', type=float, default=99.9, help="请在该参数后面加上总花了多少钱!")
return parser
def run(args):
print(f"您这次共买了{args.Apple}个苹果,{args.Banana}根香蕉,以及{args.Cherry}颗樱桃,累计消费{args.m}元!")
if __name__ == '__main__':
parser = get_parser()
args = parser.parse_args()
run(args)
更多 python 的使用方法和应用,敬请关注后续更新~