【python】命令行传参,sys VS argparse

一、前言

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 的使用方法和应用,敬请关注后续更新~

  • 17
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今夕晚风依旧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值